github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/crypto/cipher/scrypt.go (about) 1 // Copyright (C) 2017 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 package cipher 20 21 import ( 22 "bytes" 23 "crypto/aes" 24 "crypto/cipher" 25 "encoding/hex" 26 "encoding/json" 27 "errors" 28 29 "github.com/satori/go.uuid" 30 "github.com/sixexorg/magnetic-ring/common" 31 "golang.org/x/crypto/scrypt" 32 ) 33 34 const ( 35 // ScryptKDF name 36 ScryptKDF = "scrypt" 37 38 // StandardScryptN N parameter of Scrypt encryption algorithm 39 StandardScryptN = 1 << 12 //TODO: check 1<<12 vs 1<<18 40 41 // StandardScryptR r parameter of Scrypt encryption algorithm 42 StandardScryptR = 8 43 44 // StandardScryptP p parameter of Scrypt encryption algorithm 45 StandardScryptP = 1 46 47 // ScryptDKLen get derived key length 48 ScryptDKLen = 32 49 50 // cipher the name of cipher 51 cipherName = "aes-128-ctr" 52 53 // version compatible with ethereum, the version start with 3 54 version3 = 3 55 currentVersion = 4 56 57 // mac calculate hash type 58 macHash = "sha3256" 59 ) 60 61 var ( 62 // ErrVersionInvalid version not supported 63 ErrVersionInvalid = errors.New("version not supported") 64 65 // ErrKDFInvalid cipher not supported 66 ErrKDFInvalid = errors.New("kdf not supported") 67 68 // ErrCipherInvalid cipher not supported 69 ErrCipherInvalid = errors.New("cipher not supported") 70 71 // ErrDecrypt decrypt failed 72 ErrDecrypt = errors.New("could not decrypt key with given passphrase") 73 ) 74 75 type cipherparamsJSON struct { 76 IV string `json:"iv"` 77 } 78 79 type cryptoJSON struct { 80 Cipher string `json:"cipher"` 81 CipherText string `json:"ciphertext"` 82 CipherParams cipherparamsJSON `json:"cipherparams"` 83 KDF string `json:"kdf"` 84 KDFParams map[string]interface{} `json:"kdfparams"` 85 MAC string `json:"mac"` 86 MACHash string `json:"machash"` 87 } 88 89 type encryptedKeyJSON struct { 90 Address string `json:"address"` 91 Crypto cryptoJSON `json:"crypto"` 92 ID string `json:"id"` 93 Version int `json:"version"` 94 } 95 96 // Scrypt scrypt encrypt 97 type Scrypt struct { 98 } 99 100 // EncryptKey encrypt key with address 101 func (s *Scrypt) EncryptKey(address string, data []byte, passphrase []byte) ([]byte, error) { 102 crypto, err := s.scryptEncrypt(data, passphrase, StandardScryptN, StandardScryptR, StandardScryptP) 103 if err != nil { 104 return nil, err 105 } 106 v4, err := uuid.NewV4() 107 if err != nil { 108 return nil, err 109 } 110 encryptedKeyJSON := encryptedKeyJSON{ 111 string(address), 112 *crypto, 113 v4.String(), 114 currentVersion, 115 } 116 return json.Marshal(encryptedKeyJSON) 117 } 118 119 // Encrypt scrypt encrypt 120 func (s *Scrypt) Encrypt(data []byte, passphrase []byte) ([]byte, error) { 121 return s.ScryptEncrypt(data, passphrase, StandardScryptN, StandardScryptR, StandardScryptP) 122 } 123 124 // ScryptEncrypt encrypts a key using the specified scrypt parameters into a json 125 // blob that can be decrypted later on. 126 // N is a CPU/memory cost parameter, which must be a power of two greater than 1. 127 // r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the 128 // limits, the function returns a nil byte slice and an error. 129 func (s *Scrypt) ScryptEncrypt(data []byte, passphrase []byte, N, r, p int) ([]byte, error) { 130 crypto, err := s.scryptEncrypt(data, passphrase, N, r, p) 131 if err != nil { 132 return nil, err 133 } 134 return json.Marshal(crypto) 135 } 136 137 func (s *Scrypt) scryptEncrypt(data []byte, passphrase []byte, N, r, p int) (*cryptoJSON, error) { 138 salt := common.RandomCSPRNG(ScryptDKLen) 139 derivedKey, err := scrypt.Key(passphrase, salt, N, r, p, ScryptDKLen) 140 if err != nil { 141 return nil, err 142 } 143 encryptKey := derivedKey[:16] 144 145 iv := common.RandomCSPRNG(aes.BlockSize) // 16 146 cipherText, err := s.aesCTRXOR(encryptKey, data, iv) 147 if err != nil { 148 return nil, err 149 } 150 151 mac := common.Sha256(derivedKey[16:32], cipherText, iv, []byte(cipherName)) 152 153 scryptParamsJSON := make(map[string]interface{}, 5) 154 scryptParamsJSON["n"] = N 155 scryptParamsJSON["r"] = r 156 scryptParamsJSON["p"] = p 157 scryptParamsJSON["dklen"] = ScryptDKLen 158 scryptParamsJSON["salt"] = hex.EncodeToString(salt) 159 160 cipherParamsJSON := cipherparamsJSON{ 161 IV: hex.EncodeToString(iv), 162 } 163 164 crypto := &cryptoJSON{ 165 Cipher: cipherName, 166 CipherText: hex.EncodeToString(cipherText), 167 CipherParams: cipherParamsJSON, 168 KDF: ScryptKDF, 169 KDFParams: scryptParamsJSON, 170 MAC: hex.EncodeToString(mac), 171 MACHash: macHash, 172 } 173 return crypto, nil 174 } 175 176 func (s *Scrypt) aesCTRXOR(key, inText, iv []byte) ([]byte, error) { 177 aesBlock, err := aes.NewCipher(key) 178 if err != nil { 179 return nil, err 180 } 181 stream := cipher.NewCTR(aesBlock, iv) 182 outText := make([]byte, len(inText)) 183 stream.XORKeyStream(outText, inText) 184 return outText, err 185 } 186 187 // Decrypt decrypts data from a json blob, returning the origin data 188 func (s *Scrypt) Decrypt(data []byte, passphrase []byte) ([]byte, error) { 189 crypto := new(cryptoJSON) 190 if err := json.Unmarshal(data, crypto); err != nil { 191 return nil, err 192 } 193 return s.scryptDecrypt(crypto, passphrase, currentVersion) 194 } 195 196 // DecryptKey decrypts a key from a json blob, returning the private key itself. 197 func (s *Scrypt) DecryptKey(keyjson []byte, passphrase []byte) ([]byte, error) { 198 keyJSON := new(encryptedKeyJSON) 199 if err := json.Unmarshal(keyjson, keyJSON); err != nil { 200 return nil, err 201 } 202 version := keyJSON.Version 203 if version != currentVersion && version != version3 { 204 return nil, ErrVersionInvalid 205 } 206 return s.scryptDecrypt(&keyJSON.Crypto, passphrase, version) 207 } 208 209 func (s *Scrypt) scryptDecrypt(crypto *cryptoJSON, passphrase []byte, version int) ([]byte, error) { 210 211 if crypto.Cipher != cipherName { 212 return nil, ErrCipherInvalid 213 } 214 215 mac, err := hex.DecodeString(crypto.MAC) 216 if err != nil { 217 return nil, err 218 } 219 220 iv, err := hex.DecodeString(crypto.CipherParams.IV) 221 if err != nil { 222 return nil, err 223 } 224 225 cipherText, err := hex.DecodeString(crypto.CipherText) 226 if err != nil { 227 return nil, err 228 } 229 230 salt, err := hex.DecodeString(crypto.KDFParams["salt"].(string)) 231 if err != nil { 232 return nil, err 233 } 234 235 dklen := ensureInt(crypto.KDFParams["dklen"]) 236 var derivedKey = []byte{} 237 if crypto.KDF == ScryptKDF { 238 n := ensureInt(crypto.KDFParams["n"]) 239 r := ensureInt(crypto.KDFParams["r"]) 240 p := ensureInt(crypto.KDFParams["p"]) 241 derivedKey, err = scrypt.Key(passphrase, salt, n, r, p, dklen) 242 if err != nil { 243 return nil, err 244 } 245 } else { 246 return nil, ErrKDFInvalid 247 } 248 249 var calculatedMAC []byte 250 251 if version == currentVersion { 252 calculatedMAC = common.Sha256(derivedKey[16:32], cipherText, iv, []byte(crypto.Cipher)) 253 } else if version == version3 { 254 calculatedMAC = common.Sha256(derivedKey[16:32], cipherText) 255 //if crypto.MACHash != macHash { 256 // // compatible ethereum keystore file, 257 // calculatedMAC = hash.Keccak256(derivedKey[16:32], cipherText) 258 //} 259 } else { 260 return nil, ErrVersionInvalid 261 } 262 263 if !bytes.Equal(calculatedMAC, mac) { 264 return nil, ErrDecrypt 265 } 266 267 key, err := s.aesCTRXOR(derivedKey[:16], cipherText, iv) 268 if err != nil { 269 return nil, err 270 } 271 return key, nil 272 } 273 274 // because json.Unmarshal change int to float64, convert to int 275 func ensureInt(x interface{}) int { 276 res, ok := x.(int) 277 if !ok { 278 res = int(x.(float64)) 279 } 280 return res 281 }