Пример #1
0
        // TODO: Parametrize on cipher!
        // TODO: Factor out shared code between Encrypt and Decrypt!
        // TODO: Validate parameters better!
        public static byte[] Decrypt(SjclAes aes, byte[] ciphertext, byte[] iv, byte[] adata, int tagLength)
        {
            var ivLength = iv.Length;

            if (ivLength < 7)
            {
                throw new CryptoException("IV must be at least 7 bytes long");
            }

            var plaintextLength = ciphertext.Length - tagLength;
            var ciphertextOnly  = ciphertext.Take(plaintextLength).ToArray();
            var tag             = new SjclQuad(ciphertext, plaintextLength);

            var inputLengthLength = ComputeLengthLength(plaintextLength);

            if (inputLengthLength < 15 - ivLength)
            {
                inputLengthLength = 15 - ivLength;
            }
            iv = iv.Take(15 - inputLengthLength).ToArray();

            var plaintextWithTag = ApplyCtr(aes, ciphertextOnly, iv, tag, tagLength, inputLengthLength);
            var expectedTag      = ComputeTag(aes, plaintextWithTag.Text, iv, adata, tagLength, inputLengthLength);

            var expectedTagBytes = expectedTag.ToBytes().Take(tagLength);
            var actualTagBytes   = plaintextWithTag.Tag.ToBytes().Take(tagLength);

            if (!actualTagBytes.SequenceEqual(expectedTagBytes))
            {
                throw new CryptoException("CCM tag doesn't match");
            }

            return(plaintextWithTag.Text);
        }
Пример #2
0
        internal static SjclQuad ComputeTag(SjclAes aes, byte[] plaintext, byte[] iv, byte[] adata, int tagLength, int plaintextLengthLength)
        {
            if (tagLength % 2 != 0 || tagLength < 4 || tagLength > 16)
            {
                throw new CryptoException("Tag must be 4, 8, 10, 12, 14 or 16 bytes long");
            }

            // flags + iv + plaintext-length
            var tag   = new SjclQuad(iv, -1);
            var flags = (adata.Length > 0 ? 0x40 : 0) | ((tagLength - 2) << 2) | (plaintextLengthLength - 1);

            tag.SetByte(0, (byte)flags);

            // Append plaintext length
            for (var i = 0; i < plaintextLengthLength; ++i)
            {
                tag.SetByte(15 - i, (byte)(plaintext.Length >> i * 8));
            }

            tag = aes.Encrypt(tag);

            var adataLength = adata.Length;

            if (adataLength > 0)
            {
                var adataWithLength = EncodeAdataLength(adataLength).Concat(adata).ToArray();
                for (var i = 0; i < adataWithLength.Length; i += 16)
                {
                    tag = aes.Encrypt(tag ^ new SjclQuad(adataWithLength, i));
                }
            }

            for (var i = 0; i < plaintext.Length; i += 16)
            {
                tag = aes.Encrypt(tag ^ new SjclQuad(plaintext, i));
            }

            return(tag);
        }
Пример #3
0
        // TODO: Parametrize on cipher!
        public static byte[] Encrypt(SjclAes aes, byte[] plaintext, byte[] iv, byte[] adata, int tagLength)
        {
            var ivLength = iv.Length;

            if (ivLength < 7)
            {
                throw new CryptoException("IV must be at least 7 bytes long");
            }

            var inputLengthLength = ComputeLengthLength(plaintext.Length);

            if (inputLengthLength < 15 - ivLength)
            {
                inputLengthLength = 15 - ivLength;
            }
            iv = iv.Take(15 - inputLengthLength).ToArray();

            var tag           = ComputeTag(aes, plaintext, iv, adata, tagLength, inputLengthLength);
            var ciphertextTag = ApplyCtr(aes, plaintext, iv, tag, tagLength, inputLengthLength);

            return(ciphertextTag.Text.Concat(ciphertextTag.Tag.ToBytes().Take(tagLength)).ToArray());
        }
Пример #4
0
        internal static CtrResult ApplyCtr(SjclAes aes, byte[] plaintext, byte[] iv, SjclQuad tag, int tagLength, int plaintextLengthLength)
        {
            // plaintextLength + iv
            var ctr = new SjclQuad(iv, -1);

            ctr.SetByte(0, (byte)(plaintextLengthLength - 1));

            // Encrypt the tag
            var encryptedTag = tag ^ aes.Encrypt(ctr);

            // Encrypt the plaintext
            var ciphertext = new byte[plaintext.Length];

            for (var i = 0; i < plaintext.Length; i += 16)
            {
                ++ctr.D;
                var block = new SjclQuad(plaintext, i) ^ aes.Encrypt(ctr);
                Array.Copy(block.ToBytes(), 0, ciphertext, i, Math.Min(16, plaintext.Length - i));
            }

            return(new CtrResult(ciphertext, encryptedTag));
        }
Пример #5
0
        // TODO: See how this could be optimized to reuse AES object w/o recreating it every time!
        public static byte[] DecryptAes256Ccm(byte[] key, byte[] ciphertext, byte[] iv)
        {
            var aes = new SjclAes(key);

            return(SjclCcm.Decrypt(aes, ciphertext, iv, new byte[0], 8));
        }