public byte[] AES_Decrypt_GCM(byte[] cryptBytes, byte[] Key, byte[] IV, int ks) { byte[] iv; List <byte> temp = new List <byte> (); temp.AddRange(IV); temp.AddRange(cryptBytes.Take(8).ToArray()); iv = temp.ToArray(); /* * The counter array (starting at 2) * */ byte[] incr = BitConverter.GetBytes((int)2); Array.Reverse(incr); /* * Counter = First 4 bytes of IV + 8 Random bytes + 4 bytes of sequential value (starting at 2) * */ temp.Clear(); temp.TrimExcess(); temp.AddRange(iv); temp.AddRange(incr); byte[] counter = temp.ToArray(); this.aesctr = new AES_CTR(counter, ks); this.ctrenc = aesctr.CreateEncryptor(Key, null); byte[] output = new byte[81920]; int numBytes = this.ctrenc.TransformBlock(cryptBytes.Skip(8).Take(cryptBytes.Length - 16).ToArray(), 0, cryptBytes.Length - 8 - 16, output, 0); return(output.Take(numBytes).ToArray()); }
/* * Receiving seqNum as UInt64 and content_type as byte * */ public byte[] AES_Encrypt_GCM(byte[] client_write_key, byte[] client_write_iv, byte[] plaintext, UInt64 seqNum, byte content_type, int ks, Common cf) { this.cf = cf; /* * Calculate plaintext size to use later * */ int plaintext_size = plaintext.Length; /* * Initialize a temp list * */ List <byte> temp = new List <byte>(); /* * Encrypt a block of 0's and using the key * The result will be H_client * */ byte[] init_bytes = new byte[16]; Array.Clear(init_bytes, 0, 16); byte[] encrypted = AES_Encrypt_ECB(init_bytes, client_write_key, ks); Array.Reverse(encrypted); BigInteger H_client = new BigInteger(encrypted); /* * BigInteger class considers numbers with MSB (Most Significant Bit) set, as negative. * In such a case, an extra byte 00 is added to the number and converted back to BigInteger * More details at the end of the following article: * * https://msdn.microsoft.com/en-us/library/system.numerics.biginteger(v=vs.110).aspx */ if (H_client < 0) { temp.Clear(); temp.TrimExcess(); temp.AddRange(H_client.ToByteArray()); temp.Add(0); H_client = new BigInteger(temp.ToArray()); } /* * Create random number to calculate IV + random * This is concatenated with a counter array and passed to AES_CTR class * */ Random rnd = new Random(); byte[] random = new byte[8]; rnd.NextBytes(random); /* * The counter array (starting at 2) * */ byte[] incr = BitConverter.GetBytes((int)2); Array.Reverse(incr); /* * Counter = First 4 bytes of IV + 8 Random bytes + 4 bytes of sequential value (starting at 2) * */ temp.Clear(); temp.TrimExcess(); temp.AddRange(client_write_iv); temp.AddRange(random); byte[] iv = temp.ToArray(); temp.AddRange(incr); byte[] counter = temp.ToArray(); /* * ctext == Cipher Text * */ byte[] ctext; /* * Plaintext is 16 bytes for Handshake message. Hence, we use TransformFinalBlock here * */ this.aesctr = new AES_CTR(counter, ks); this.ctrenc = aesctr.CreateEncryptor(client_write_key, null); ctext = this.ctrenc.TransformFinalBlock(plaintext, 0, plaintext_size); /* * Now creating the AAD * AAD = Sequence Number + Content Type + TLS Version + Plaintext Size * */ byte[] seq_num = BitConverter.GetBytes(seqNum); Array.Reverse(seq_num); /* * Using UInt16 instead of short * */ byte[] tls_version = BitConverter.GetBytes((UInt16)771); byte[] plaintext_size_array = BitConverter.GetBytes((UInt16)plaintext_size); /* * Size was returned as 10 00 instead of 00 10 * */ Array.Reverse(plaintext_size_array); temp.Clear(); temp.TrimExcess(); temp.AddRange(seq_num); temp.Add(content_type); temp.AddRange(tls_version); temp.AddRange(plaintext_size_array); byte[] auth_data = temp.ToArray(); /* * Calculating Auth Tag using GHASH function * */ BigInteger auth_tag = GHASH(H_client, auth_data, ctext); /* * E = ENCRYPTION(IV + "\x00\x00\x00\x01") * Auth Tag = Auth Tag ^ E * */ byte[] cval = { 0, 0, 0, 1 }; temp.Clear(); temp.TrimExcess(); temp.AddRange(iv); temp.AddRange(cval); byte[] encrypted1 = AES_Encrypt_ECB(temp.ToArray(), client_write_key, ks); Array.Reverse(encrypted1); BigInteger nenc = new BigInteger(encrypted1); /* * Again if nenc is less than 0, we append a byte of 00 to the end, and convert it back * */ if (nenc < 0) { temp.Clear(); temp.TrimExcess(); temp.AddRange(nenc.ToByteArray()); temp.Add(0); nenc = new BigInteger(temp.ToArray()); } auth_tag ^= nenc; /* * ToByteArray has to be inverted * */ byte[] auth_tag_array = auth_tag.ToByteArray(); Array.Reverse(auth_tag_array); if (auth_tag_array[0] == 0x00) { auth_tag_array = auth_tag_array.Skip(1).ToArray(); } temp.Clear(); temp.TrimExcess(); /* * Sending random + cipher text + auth_tag_array * */ temp.AddRange(random); temp.AddRange(ctext); temp.AddRange(auth_tag_array); return(temp.ToArray()); }