Beispiel #1
0
        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);
        }
Beispiel #2
0
        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());
        }
Beispiel #3
0
 internal static void ValidateB(BigInteger sharedB)
 {
     if (sharedB % SirpN == 0)
     {
         throw ExceptionFactory.MakeInvalidOperation("SRP: B validation failed");
     }
 }
Beispiel #4
0
        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);
            }
        }
Beispiel #5
0
        public RsaKey GetRsa(string id)
        {
            if (!_rsa.ContainsKey(id))
            {
                throw ExceptionFactory.MakeInvalidOperation(
                          string.Format("Keychain: RSA key '{0}' not found", id));
            }

            return(_rsa[id]);
        }
Beispiel #6
0
        public AesKey GetAes(string id)
        {
            if (!_aes.ContainsKey(id))
            {
                throw ExceptionFactory.MakeInvalidOperation(
                          string.Format("Keychain: AES key '{0}' not found", id));
            }

            return(_aes[id]);
        }
Beispiel #7
0
        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));
        }
Beispiel #8
0
        //
        // 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]);
                        }
                    }
                }
        }
Beispiel #9
0
        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]));
        }
Beispiel #10
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());
        }
Beispiel #11
0
        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));
            }
        }
Beispiel #12
0
        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);
        }