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); }
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)); }