コード例 #1
0
ファイル: FileKeyStore.cs プロジェクト: prestwich/nethermind
        public (PrivateKey PrivateKey, Result Result) GetKey(Address address, SecureString password)
        {
            if (!password.IsReadOnly())
            {
                throw new InvalidOperationException("Cannot work with password that is not readonly");
            }

            var serializedKey = ReadKey(address);

            if (serializedKey == null)
            {
                return(null, Result.Fail("Cannot find key"));
            }
            var keyStoreItem = _jsonSerializer.Deserialize <KeyStoreItem>(serializedKey);

            if (keyStoreItem?.Crypto == null)
            {
                return(null, Result.Fail("Cannot deserialize key"));
            }

            var validationResult = Validate(keyStoreItem);

            if (validationResult.ResultType != ResultType.Success)
            {
                return(null, validationResult);
            }

            byte[] mac    = Bytes.FromHexString(keyStoreItem.Crypto.MAC);
            byte[] iv     = Bytes.FromHexString(keyStoreItem.Crypto.CipherParams.IV);
            byte[] cipher = Bytes.FromHexString(keyStoreItem.Crypto.CipherText);
            byte[] salt   = Bytes.FromHexString(keyStoreItem.Crypto.KDFParams.Salt);

            var kdfParams = keyStoreItem.Crypto.KDFParams;
            var passBytes = password.ToByteArray(_keyStoreEncoding);

            byte[] derivedKey;
            var    kdf = keyStoreItem.Crypto.KDF.Trim();

            switch (kdf)
            {
            case "scrypt":
                int r = kdfParams.R.Value;
                int p = kdfParams.P.Value;
                int n = kdfParams.N.Value;
                derivedKey = SCrypt.ComputeDerivedKey(passBytes, salt, n, r, p, null, kdfParams.DkLen);
                break;

            case "pbkdf2":
                int c           = kdfParams.C.Value;
                var deriveBytes = new Rfc2898DeriveBytes(passBytes, salt, kdfParams.C.Value, HashAlgorithmName.SHA256);
                derivedKey = deriveBytes.GetBytes(256);
                break;

            default:
                return(null, Result.Fail($"Unsupported algoritm: {kdf}"));
            }

            var restoredMac = Keccak.Compute(derivedKey.Slice(kdfParams.DkLen - 16, 16).Concat(cipher).ToArray()).Bytes;

            if (!Bytes.AreEqual(mac, restoredMac))
            {
                return(null, Result.Fail("Incorrect MAC"));
            }

            var cipherType = keyStoreItem.Crypto.Cipher.Trim();

            byte[] decryptKey;
            if (kdf == "scrypt" && cipherType == "aes-128-cbc")
            {
                decryptKey = Keccak.Compute(derivedKey.Slice(0, 16)).Bytes.Slice(0, 16);
            }
            else
            {
                decryptKey = derivedKey.Slice(0, 16);
            }

            byte[] key = _symmetricEncrypter.Decrypt(cipher, decryptKey, iv, cipherType);
            if (key == null)
            {
                return(null, Result.Fail("Error during decryption"));
            }

            // TODO: maybe only allow to sign here so the key never leaves the area?
            return(new PrivateKey(key), Result.Success);
        }
コード例 #2
0
        public (PrivateKey PrivateKey, Result Result) GetKey(Address address, SecureString password)
        {
            var serializedKey = ReadKey(address.ToString());

            if (serializedKey == null)
            {
                return(null, Result.Fail("Cannot find key"));
            }
            var keyStoreItem = _jsonSerializer.Deserialize <KeyStoreItem>(serializedKey);

            if (keyStoreItem?.Crypto == null)
            {
                return(null, Result.Fail("Cannot deserialize key"));
            }

            var validationResult = Validate(keyStoreItem);

            if (validationResult.ResultType != ResultType.Success)
            {
                return(null, validationResult);
            }

            Hex mac    = keyStoreItem.Crypto.MAC;
            Hex iv     = keyStoreItem.Crypto.CipherParams.IV;
            Hex cipher = keyStoreItem.Crypto.CipherText;
            Hex salt   = keyStoreItem.Crypto.KDFParams.Salt;

            var kdfParams = keyStoreItem.Crypto.KDFParams;
            var passBytes = password.ToByteArray(_keyStoreEncoding);

            byte[] derivedKey;
            var    kdf = keyStoreItem.Crypto.KDF.Trim();

            switch (kdf)
            {
            case "scrypt":
                derivedKey = SCrypt.ComputeDerivedKey(passBytes, salt, kdfParams.N, kdfParams.R, kdfParams.P, null, kdfParams.DkLen);
                break;

            case "pbkdf2":
                var deriveBytes = new Rfc2898DeriveBytes(passBytes, salt, kdfParams.C, HashAlgorithmName.SHA256);
                derivedKey = deriveBytes.GetBytes(256);
                break;

            default:
                return(null, Result.Fail($"Unsupported algoritm: {kdf}"));
            }

            var restoredMac = Keccak.Compute(derivedKey.Slice(kdfParams.DkLen - 16, 16).Concat((byte[])cipher).ToArray()).Bytes;

            if (!mac.Equals(new Hex(restoredMac)))
            {
                return(null, Result.Fail("Incorrect MAC"));
            }

            var cipherType = keyStoreItem.Crypto.Cipher.Trim();

            byte[] decryptKey;
            if (kdf == "scrypt" && cipherType == "aes-128-cbc")
            {
                decryptKey = Keccak.Compute(derivedKey.Slice(0, 16)).Bytes.Slice(0, 16);
            }
            else
            {
                decryptKey = derivedKey.Slice(0, 16);
            }

            byte[] key = _symmetricEncrypter.Decrypt(cipher, decryptKey, iv, cipherType);
            if (key == null)
            {
                return(null, Result.Fail("Error during decryption"));
            }

            // TODO: maybe only allow to sign here so the key never leaves the area?
            return(new PrivateKey(new Hex(key)), Result.Success());
        }