예제 #1
0
        public CtrStream(Stream input, byte[] key, byte[] ctr, bool littleEndianCtr)
        {
            if (key.Length / 4 < 4 || key.Length / 4 > 8 || key.Length % 4 > 0)
            {
                throw new InvalidOperationException("Key has invalid length.");
            }

            if (ctr.Length != BlockSize)
            {
                throw new InvalidOperationException("Counter has invalid length.");
            }

            if (input.Length % BlockSize != 0)
            {
                throw new InvalidOperationException("Stream needs to have a length dividable by 16.");
            }

            _baseStream = input;

            _initialCtr = new byte[ctr.Length];
            Array.Copy(ctr, _initialCtr, ctr.Length);
            _currentCtr = new byte[ctr.Length];
            Array.Copy(ctr, _currentCtr, ctr.Length);

            _internalLength  = input.Length;
            _lastBlockBuffer = new byte[BlockSize];
            _littleEndianCtr = littleEndianCtr;

            var aes = AesCtr.Create(littleEndianCtr);

            _decryptor = (AesCtrCryptoTransform)aes.CreateDecryptor(key, ctr);
            _encryptor = (AesCtrCryptoTransform)aes.CreateEncryptor(key, ctr);
        }
예제 #2
0
        public static byte[] CTR128(byte[] block, byte[] key, byte[] ctr)
        {
            var aes = new AesCtr(ctr);

            var output = new byte[block.Length];

            aes.CreateDecryptor(key).TransformBlock(block, 0, block.Length, output, 0);
            return(output);
        }
예제 #3
0
        public void TestEncrypt()
        {
            foreach (var example in LoadExamples())
            {
                var key       = Hex.Decode(example.Key);
                var iv        = Hex.Decode(example.Iv);
                var plaintext = Hex.Decode(example.Plaintext);

                using (var ctr = new AesCtr(key, iv))
                {
                    ctr.Encrypt(plaintext, 0, plaintext.Length, plaintext, 0);
                    Assert.Equal(example.Ciphertext, Hex.Encode(plaintext));
                }
            }
        }
예제 #4
0
        public void TestChallenge18()
        {
            var   encrypted = Convert.FromBase64String(Set3Data.Challenge18Input);
            var   keyStr    = "YELLOW SUBMARINE";
            var   key       = System.Text.Encoding.ASCII.GetBytes(keyStr);
            ulong nonce     = 0;

            var decrypted = AesCtr.Decrypt(key, nonce, encrypted);
            var actual    = System.Text.Encoding.ASCII.GetString(decrypted);

            Assert.AreEqual(Set3Data.Challenge18Solution, actual);

            // Encrypt and verify against input data
            var enc = AesCtr.Encrypt(key, nonce, decrypted);

            CollectionAssert.AreEqual(encrypted, enc);
        }
예제 #5
0
        public void Aes128CtrDecrypt(string plainString, string encryptedHexString)
        {
            // Obtain the key.
            byte[] key = "7b6dcbffad4bbbcd25e2a80201739233".HexToBytes();

            // Obtain the data as bytes.
            byte[] encryptedData = encryptedHexString.HexToBytes();

            // Decrypt the provided data.
            byte[] resultData   = AesCtr.Decrypt(key, encryptedData, null);
            string resultString = Encoding.UTF8.GetString(resultData);

            // Assert the data is the same length
            Assert.Equal(plainString.Length, resultString.Length);

            // Verify the string equals the original string.
            Assert.Equal(plainString, resultString);
        }
예제 #6
0
        public void Aes256CtrEncrypt(string plainString, string encryptedHexString)
        {
            // Obtain the key.
            byte[] key = "7b6dcbffad4bbbcd25e2a802017392337b6dcbffad4bbbcd25e2a80201739233".HexToBytes();

            // Obtain the data as bytes.
            byte[] plainData = Encoding.UTF8.GetBytes(plainString);

            // Encrypt the provided data.
            byte[] resultData      = AesCtr.Encrypt(key, plainData, null);
            string resultHexString = resultData.ToHexString(false);

            // Assert the data is the same length
            Assert.Equal(plainData.Length, resultData.Length);

            // Verify the string equals the original string.
            Assert.Equal(encryptedHexString, resultHexString, true);
        }
예제 #7
0
        public void Aes192CtrEncryptDecrypt(string testString)
        {
            // Generate a random key.
            byte[] key = new byte[24]; // 192 bit
            RandomNumberGenerator random = RandomNumberGenerator.Create();

            random.GetBytes(key);

            // Obtain the data as bytes.
            byte[] testData = Encoding.UTF8.GetBytes(testString);

            // Encrypt then decrypt the data.
            byte[] encrypted = AesCtr.Encrypt(key, testData);
            byte[] decrypted = AesCtr.Decrypt(key, encrypted);

            // Get the decrypted result as a string
            string result = Encoding.UTF8.GetString(decrypted);

            // Verify the string equals the original string.
            Assert.Equal(testString, result);
        }
예제 #8
0
        [InlineData("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6")] // AES-256-CTR
        public void AesCtrTestWithNISTVectors(string keyHexString, string counterHexString, string plainTextHexString, string cipherTextHexString)
        {
            // Obtain the components as bytes.
            byte[] key           = keyHexString.HexToBytes();
            byte[] counter       = counterHexString.HexToBytes();
            byte[] plainTextData = plainTextHexString.HexToBytes();

            // Encrypt the provided data.
            byte[] encryptedData          = AesCtr.Encrypt(key, plainTextData, counter);
            string encryptedDataHexString = encryptedData.ToHexString(false);

            // Assert this equals our ciphered text
            Assert.Equal(cipherTextHexString, encryptedDataHexString, true);

            // Decrypt the data back to it's original format
            byte[] decryptedData          = AesCtr.Decrypt(key, encryptedData, counter);
            string decryptedDataHexString = decryptedData.ToHexString(false);

            // Assert this equals our plain text
            Assert.Equal(plainTextHexString, decryptedDataHexString, true);
        }
예제 #9
0
        public void TestLargeMessage()
        {
            var key      = new byte[16];
            var iv       = new byte[16];
            var message  = new byte[10000];
            var last     = new byte[16];
            var expected = "3b9a44f22bb1522f10c00ff8ca5195ea";

            // Test encrypting the whole message

            using (var ctr = new AesCtr(key, iv))
            {
                ctr.Encrypt(message, 0, message.Length, message, 0);
                Array.Copy(message, message.Length - last.Length, last, 0, last.Length);
                Assert.Equal(expected, Hex.Encode(last));
            }

            // Test encrypting the message in chunks

            using (var ctr = new AesCtr(key, iv))
            {
                Array.Clear(message, 0, message.Length);

                var seg       = new ArraySegment <byte>(message);
                var chunkSize = 137;

                while (seg.Count > 0)
                {
                    ctr.Encrypt(seg.Array, seg.Offset, seg.Count, message, 0);
                    seg = seg.Slice(Math.Min(seg.Count, chunkSize));
                }

                Array.Copy(message, message.Length - last.Length, last, 0, last.Length);
                Assert.Equal(expected, Hex.Encode(last));
            }
        }
예제 #10
0
        public static byte[] Encrypt(EthereumEcdsa remotePublicKey, byte[] data, byte[] sharedMacData = null)
        {
            // If we have no shared mac data, we set it as a blank array
            sharedMacData = sharedMacData ?? Array.Empty <byte>();

            // Generate a random private key
            EthereumEcdsa senderPrivateKey = EthereumEcdsa.Generate(new SystemRandomAccountDerivation());

            // Generate the elliptic curve diffie hellman ("ECDH") shared key
            byte[] ecdhKey = senderPrivateKey.ComputeECDHKey(remotePublicKey);

            // Perform NIST SP 800-56 Concatenation Key Derivation Function ("KDF")
            Memory <byte> keyData = DeriveKeyKDF(ecdhKey, 32);

            // Split the AES encryption key and MAC from the derived key data.
            var aesKey = keyData.Slice(0, 16).ToArray();

            byte[] hmacSha256Key = keyData.Slice(16, 16).ToArray();
            hmacSha256Key = _sha256.ComputeHash(hmacSha256Key);

            // We generate a counter for our aes-128-ctr operation.
            byte[] counter = new byte[AesCtr.BLOCK_SIZE];
            _randomNumberGenerator.GetBytes(counter);

            // Encrypt the data accordingly.
            byte[] encryptedData = AesCtr.Encrypt(aesKey, data, counter);

            // Obtain the sender's public key to compile our message.
            byte[] localPublicKey = senderPrivateKey.ToPublicKeyArray(false, true);

            // We'll want to put this data into the message in the following order (where || is concatenation):
            // ECIES_HEADER_BYTE (1 byte) || sender's public key (64 bytes) || counter (16 bytes) || encrypted data (arbitrary length) || tag (32 bytes)
            // This gives us a total size of 113 + data.Length
            byte[] result = new byte[ECIES_ADDITIONAL_OVERHEAD + encryptedData.Length];

            // Define a pointer and copy in our data as suggested.
            int offset = 0;

            result[offset++] = ECIES_HEADER_BYTE;
            Array.Copy(localPublicKey, 0, result, offset, localPublicKey.Length);
            offset += localPublicKey.Length;
            Array.Copy(counter, 0, result, offset, counter.Length);
            offset += counter.Length;
            Array.Copy(encryptedData, 0, result, offset, encryptedData.Length);
            offset += encryptedData.Length;

            // We still have to copy the tag, which is a HMACSHA256 of our counter + encrypted data + shared mac.

            // We copy the data into a buffer for this hash computation since counter + encrypted data are already aligned.
            byte[] tagPreimage = new byte[counter.Length + encryptedData.Length + sharedMacData.Length];
            Array.Copy(result, 65, tagPreimage, 0, counter.Length + encryptedData.Length);
            Array.Copy(sharedMacData, 0, tagPreimage, counter.Length + encryptedData.Length, sharedMacData.Length);

            // Obtain a HMACSHA256 provider
            HMACSHA256 hmacSha256 = new HMACSHA256(hmacSha256Key);

            // Compute a hash of our counter + encrypted data + shared mac data.
            byte[] tag = hmacSha256.ComputeHash(tagPreimage);

            // Copy the tag into our result buffer.
            Array.Copy(tag, 0, result, offset, tag.Length);
            offset += tag.Length;

            // Return the resulting data.
            return(result);
        }
예제 #11
0
        public static byte[] Decrypt(EthereumEcdsa localPrivateKey, Memory <byte> message, Memory <byte> sharedMacData)
        {
            // Verify our provided key type
            if (localPrivateKey.KeyType != EthereumEcdsaKeyType.Private)
            {
                throw new ArgumentException("ECIES could not decrypt data because the provided key was not a private key.");
            }

            // Verify the size of our message (layout specified in Encrypt() describes this value)
            if (message.Length <= ECIES_ADDITIONAL_OVERHEAD)
            {
                throw new ArgumentException("ECIES could not decrypt data because the provided data did not contain enough information.");
            }

            // Verify the first byte of our data
            int offset = 0;

            if (message.Span[offset++] != ECIES_HEADER_BYTE)
            {
                throw new ArgumentException("ECIES could not decrypt data because the provided data had an invalid header.");
            }

            // Extract the sender's public key from the data.
            Memory <byte> remotePublicKeyData = message.Slice(offset, 64);
            EthereumEcdsa remotePublicKey     = EthereumEcdsa.Create(remotePublicKeyData, EthereumEcdsaKeyType.Public);

            offset += remotePublicKeyData.Length;
            Memory <byte> counter = message.Slice(offset, AesCtr.BLOCK_SIZE);

            offset += counter.Length;
            Memory <byte> encryptedData = message.Slice(offset, message.Length - offset - 32);

            offset += encryptedData.Length;
            byte[] tag = message.Slice(offset, message.Length - offset).ToArray();
            offset += tag.Length;

            // Generate the elliptic curve diffie hellman ("ECDH") shared key
            byte[] ecdhKey = localPrivateKey.ComputeECDHKey(remotePublicKey);

            // Perform NIST SP 800-56 Concatenation Key Derivation Function ("KDF")
            Memory <byte> keyData = DeriveKeyKDF(ecdhKey, 32);

            // Split the AES encryption key and MAC from the derived key data.
            var aesKey = keyData.Slice(0, 16).ToArray();

            byte[] hmacSha256Key = keyData.Slice(16, 16).ToArray();
            hmacSha256Key = _sha256.ComputeHash(hmacSha256Key);

            // Next we'll want to verify our tag (HMACSHA256 hash of counter + encrypted data + shared mac data).

            // We copy the data into a buffer for this hash computation since counter + encrypted data are already aligned.
            byte[]        tagPreimage       = new byte[counter.Length + encryptedData.Length + sharedMacData.Length];
            Memory <byte> tagPreimageMemory = tagPreimage;

            counter.CopyTo(tagPreimageMemory);
            encryptedData.CopyTo(tagPreimageMemory.Slice(counter.Length, encryptedData.Length));
            sharedMacData.CopyTo(tagPreimageMemory.Slice(counter.Length + encryptedData.Length));

            // Obtain a HMACSHA256 provider
            HMACSHA256 hmacSha256 = new HMACSHA256(hmacSha256Key);

            // Compute a hash of our counter + encrypted data + shared mac data.
            byte[] validTag = hmacSha256.ComputeHash(tagPreimage);

            // Verify our tag is valid
            if (!tag.SequenceEqual(validTag))
            {
                throw new ArgumentException("ECIES could not decrypt data because the hash/tag on the counter/encrypted data/shared mac data was invalid.");
            }

            // Decrypt the data accordingly.
            byte[] decryptedData = AesCtr.Decrypt(aesKey, encryptedData.ToArray(), counter.ToArray());

            // Return the decrypted data.
            return(decryptedData);
        }
예제 #12
0
        public void DeriveEncryptionParameters()
        {
            // Verify the session state is correct.
            if (SessionState != RLPxSessionState.AcknowledgementCompleted)
            {
                throw new Exception("RLPx encryption parameter deriviation should only occur after authentication and acknowledgement was processed.");
            }

            // Verify we have all required information
            if (AuthData == null || AuthAckData == null || RemoteEphermalPublicKey == null || InitiatorNonce == null || ResponderNonce == null)
            {
                throw new Exception("RLPx deriving encryption information failed: Insufficient data collected from handshake.");
            }

            // Generate the ecdh key with both ephemeral keys
            byte[] ecdhEphemeralKey = LocalEphemeralPrivateKey.ComputeECDHKey(RemoteEphermalPublicKey);

            // Generate a shared secret: Keccak256(ecdhEphemeralKey || Keccak256(ResponderNonce || InitiatorNonce))
            byte[] combinedNonceHash = KeccakHash.ComputeHashBytes(ResponderNonce.Concat(InitiatorNonce));
            byte[] sharedSecret      = KeccakHash.ComputeHashBytes(ecdhEphemeralKey.Concat(combinedNonceHash));

            // Derive the token as a hash of the shared secret.
            Token = KeccakHash.ComputeHashBytes(sharedSecret);

            // Derive AES secret: Keccak256(ecdhEphemeralKey || sharedSecret)
            AesSecret = KeccakHash.ComputeHashBytes(ecdhEphemeralKey.Concat(sharedSecret));

            // Derive Mac secret: Keccak256(ecdhEphemeralKey || AesSecret)
            MacSecret = KeccakHash.ComputeHashBytes(ecdhEphemeralKey.Concat(AesSecret));

            // Create our AES providers for incoming and outgoing traffic/frames.
            // Counter is 0, so it doesn't need to be provided, default value will handle this.
            IngressAes = new AesCtr(AesSecret);
            EgressAes  = new AesCtr(AesSecret);

            // Next we'll want to derive our incoming (ingress) and outgoing (egress) traffic message authentication code ("MAC")
            // The initial state is based off of keccak((MacSecret ^ nonce) || auth/auth-ack). Later states update data from packet frames.

            // We begin by calculating the xor'd nonces
            byte[] initiatorTranformedNonce  = (byte[])InitiatorNonce.Clone();
            byte[] responderTransformedNonce = (byte[])ResponderNonce.Clone();
            int    loopSize = Math.Min(initiatorTranformedNonce.Length, MacSecret.Length);

            for (int i = 0; i < loopSize; i++)
            {
                initiatorTranformedNonce[i]  ^= MacSecret[i];
                responderTransformedNonce[i] ^= MacSecret[i];
            }

            // Next we'll want to hash the data with our hash providers.
            KeccakHash initiatorOutgoing = KeccakHash.Create();

            initiatorOutgoing.Update(responderTransformedNonce, 0, responderTransformedNonce.Length);
            initiatorOutgoing.Update(AuthData, 0, AuthData.Length);
            KeccakHash responderOutgoing = KeccakHash.Create();

            responderOutgoing.Update(initiatorTranformedNonce, 0, initiatorTranformedNonce.Length);
            responderOutgoing.Update(AuthAckData, 0, AuthAckData.Length);

            // Assign the correct hash providers based off of role
            if (Role == RLPxSessionRole.Initiator)
            {
                EgressMac  = initiatorOutgoing;
                IngressMac = responderOutgoing;
            }
            else
            {
                EgressMac  = responderOutgoing;
                IngressMac = initiatorOutgoing;
            }
        }
예제 #13
0
 public static void Test()
 {
     // Taken from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
     // F.5.1 CTR-AES128.Encrypt and
     // F.5.2 CTR-AES128.Decrypt
     string[] keys = new[]
     {
         "2b7e151628aed2a6abf7158809cf4f3c",
         "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
         "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
     };
     string[] plains = new[]
     {
         "6bc1bee22e409f96e93d7e117393172a",
         "ae2d8a571e03ac9c9eb76fac45af8e51",
         "30c81c46a35ce411e5fbc1191a0a52ef",
         "f69f2445df4f9b17ad2b417be66c3710",
     };
     string[][] encrypteds = new[]
     {
         new[]
         {
             "874d6191b620e3261bef6864990db6ce",
             "9806f66b7970fdff8617187bb9fffdff",
             "5ae4df3edbd5d35e5b4f09020db03eab",
             "1e031dda2fbe03d1792170a0f3009cee",
         },
         new[]
         {
             "1abc932417521ca24f2b0459fe7e6e0b",
             "090339ec0aa6faefd5ccc2c6f4ce8e94",
             "1e36b26bd1ebc670d1bd1d665620abf7",
             "4f78a7f6d29809585a97daec58c6b050",
         },
         new[]
         {
             "601ec313775789a5b7a7f504bbf3d228",
             "f443e3ca4d62b59aca84e990cacaf5c5",
             "2b0930daa23de94ce87017ba2d84988d",
             "dfc9c58db67aada613c2dd08457941a6",
         },
     };
     for (int i = 0; i < keys.Length; i++)
     {
         var aes = new AesCtr();
         aes.Key = GetBytes(keys[i]);
         aes.IV  = GetBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
         Console.WriteLine("{0} bits", aes.KeySize);
         {
             Console.WriteLine("Encrypt");
             ICryptoTransform encryptor = aes.CreateEncryptor();
             var cipher = new byte[16];
             for (int j = 0; j < plains.Length; j++)
             {
                 byte[] plain = GetBytes(plains[j]);
                 encryptor.TransformBlock(plain, 0, plain.Length, cipher, 0);
                 string cipherHex = BitConverter.ToString(cipher).Replace("-", string.Empty).ToLowerInvariant();
                 if (cipherHex != encrypteds[i][j])
                 {
                     throw new Exception("Error encrypting " + j);
                 }
                 Console.WriteLine(cipherHex);
             }
         }
         Console.WriteLine();
         {
             Console.WriteLine("Decrypt");
             ICryptoTransform decryptor = aes.CreateDecryptor();
             var plain = new byte[16];
             for (int j = 0; j < encrypteds[i].Length; j++)
             {
                 byte[] encrypted = GetBytes(encrypteds[i][j]);
                 decryptor.TransformBlock(encrypted, 0, encrypted.Length, plain, 0);
                 string plainHex = BitConverter.ToString(plain).Replace("-", string.Empty).ToLowerInvariant();
                 if (plainHex != plains[j])
                 {
                     throw new Exception("Error decrypting " + j);
                 }
                 Console.WriteLine(plainHex);
             }
         }
         Console.WriteLine();
     }
 }