public static byte[] Decrypt(byte[] key, byte[] ciphertext, byte[] iv, byte[] authData) { if (ciphertext.Length < 16) { throw ExceptionFactory.MakeInvalidOperation( "AES-GCM: ciphertext must be at least 16 bytes long"); } var length = ciphertext.Length - 16; var plaintext = new byte[length]; var hashKey = new byte[16]; var hashSalt = new byte[16]; Crypt(key, ciphertext, length, iv, authData, plaintext, hashKey, hashSalt); var tag = ComputeTag(hashKey, hashSalt, authData, ciphertext, length); // Timing attack resistant (not that anyone cares in this case) array comparison. // XOR two arrays and bitwise sum up all the bytes. Should evaluate to 0 when // and only when the arrays are the same. int sum = 0; for (int i = 0; i < 16; ++i) { sum |= tag[i] ^ ciphertext[length + i]; } if (sum != 0) { throw ExceptionFactory.MakeInvalidOperation("AES-GCM: auth tag doesn't match"); } return(plaintext); }
internal static byte[] GHash(byte[] key, byte[] authData, int authDataLength, byte[] ciphertext, int ciphertextLength) { if (key.Length != 16) { throw ExceptionFactory.MakeInvalidOperation("AES-GCM: key must be 16 bytes long"); } var key128 = new UInt128(key); var x = new UInt128(); for (int i = 0; i < authDataLength; i += 16) { x = XorMultiply(key128, x, new UInt128(authData, i, authDataLength)); } for (int i = 0; i < ciphertextLength; i += 16) { x = XorMultiply(key128, x, new UInt128(ciphertext, i, ciphertextLength)); } var l = new UInt128(low: (ulong)ciphertextLength * 8, high: (ulong)authDataLength * 8); return(XorMultiply(key128, x, l).ToBytes()); }
internal static void ValidateB(BigInteger sharedB) { if (sharedB % SirpN == 0) { throw ExceptionFactory.MakeInvalidOperation("SRP: B validation failed"); } }
internal static void DecryptKeysets(JToken keysets, ClientInfo clientInfo, Keychain keychain) { var sorted = keysets .OrderByDescending(i => i.StringAt("encryptedBy") == MasterKeyId) // everything with "mp" goes first .ThenByDescending(i => i.IntAt("sn")) // and then is sorted by "sn" .ToArray(); if (sorted[0].StringAt("encryptedBy") != MasterKeyId) { throw ExceptionFactory.MakeInvalidOperation( string.Format("Invalid keyset (key must be encrypted by '{0}')", MasterKeyId)); } var keyInfo = sorted[0].At("encSymKey"); var masterKey = DeriveMasterKey(algorithm: keyInfo.StringAt("alg"), iterations: keyInfo.IntAt("p2c"), salt: keyInfo.StringAt("p2s").Decode64(), clientInfo: clientInfo); keychain.Add(masterKey); foreach (var i in sorted) { DecryptKeyset(i, keychain); } }
public RsaKey GetRsa(string id) { if (!_rsa.ContainsKey(id)) { throw ExceptionFactory.MakeInvalidOperation( string.Format("Keychain: RSA key '{0}' not found", id)); } return(_rsa[id]); }
public AesKey GetAes(string id) { if (!_aes.ContainsKey(id)) { throw ExceptionFactory.MakeInvalidOperation( string.Format("Keychain: AES key '{0}' not found", id)); } return(_aes[id]); }
public byte[] Decrypt(Encrypted encrypted) { switch (encrypted.Scheme) { case AesKey.EncryptionScheme: return(GetAes(encrypted.KeyId).Decrypt(encrypted)); case RsaKey.EncryptionScheme: return(GetRsa(encrypted.KeyId).Decrypt(encrypted)); } throw ExceptionFactory.MakeInvalidOperation( string.Format("Keychain: Unsupported encryption scheme '{0}'", encrypted.Scheme)); }
// // Internal // internal static void Crypt(byte[] key, byte[] input, int length, byte[] iv, byte[] authData, // output byte[] output, byte[] hashKey, byte[] hashSalt) { if (key.Length != 32) { throw ExceptionFactory.MakeInvalidOperation("AES-GCM: key must be 32 bytes long"); } if (iv.Length != 12) { throw ExceptionFactory.MakeInvalidOperation("AES-GCM: iv must be 12 bytes long"); } Debug.Assert(input.Length >= length); Debug.Assert(output.Length >= length); Debug.Assert(hashKey.Length == 16); Debug.Assert(hashSalt.Length == 16); using (var aes = new AesManaged { Mode = CipherMode.ECB, Key = key }) using (var aesEnc = aes.CreateEncryptor()) { var counter = InitializeCounter(iv); aesEnc.TransformBlock(new byte[16], 0, 16, hashKey, 0); aesEnc.TransformBlock(counter, 0, 16, hashSalt, 0); var block = new byte[16]; for (int i = 0; i < length; i += 16) { IncrementCounter(counter); aesEnc.TransformBlock(counter, 0, 16, block, 0); for (int j = 0; j < Math.Min(length - i, 16); ++j) { output[i + j] = (byte)(input[i + j] ^ block[j]); } } } }
public byte[] Decrypt(Encrypted e) { if (e.KeyId != Id) { throw ExceptionFactory.MakeInvalidOperation("AES key: mismatching key id"); } if (e.Scheme != EncryptionScheme) { throw ExceptionFactory.MakeInvalidOperation( string.Format("AES key: invalid encryption scheme '{0}', expected '{1}'", e.Scheme, EncryptionScheme)); } return(AesGcm.Decrypt(Key, e.Ciphertext, e.Iv, new byte[0])); }
internal static BigInteger ExchangeAForB(BigInteger sharedA, Session session, JsonHttpClient http) { var response = http.Post("v1/auth", new Dictionary <string, object> { { "sessionID", session.Id }, { "userA", sharedA.ToHex() } }); if (response.StringAt("sessionID") != session.Id) { throw ExceptionFactory.MakeInvalidOperation("SRP: session ID doesn't match"); } return(response.StringAt("userB").ToBigInt()); }
public byte[] Decrypt(Encrypted e) { if (e.KeyId != Id) { throw ExceptionFactory.MakeInvalidOperation("RSA key: mismatching key id"); } if (e.Scheme != EncryptionScheme) { throw ExceptionFactory.MakeInvalidOperation( string.Format("RSA key: invalid encryption scheme '{0}', expected '{1}'", e.Scheme, EncryptionScheme)); } using (var rsa = new RSACryptoServiceProvider()) { rsa.ImportParameters(Parameters); return(rsa.Decrypt(e.Ciphertext, true)); } }
public static byte[] DecodeHex(this string s) { if (s.Length % 2 != 0) { throw ExceptionFactory.MakeInvalidOperation( "DecodeHex: input length must be multiple of 2"); } var bytes = new byte[s.Length / 2]; for (var i = 0; i < s.Length / 2; ++i) { var b = 0; for (var j = 0; j < 2; ++j) { b <<= 4; var c = char.ToLower(s[i * 2 + j]); if (c >= '0' && c <= '9') { b |= c - '0'; } else if (c >= 'a' && c <= 'f') { b |= c - 'a' + 10; } else { throw ExceptionFactory.MakeInvalidOperation( "DecodeHex: input contains invalid characters"); } } bytes[i] = (byte)b; } return(bytes); }