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