public virtual void Init( bool forEncryption, ICipherParameters parameters) { _forEncryption = forEncryption; KeyParameter keyParam; if (parameters is AeadParameters) { AeadParameters param = (AeadParameters)parameters; _nonce = param.GetNonce(); _initialAssociatedText = param.GetAssociatedText(); keyParam = param.Key; } else if (parameters is ParametersWithIV) { ParametersWithIV param = (ParametersWithIV)parameters; _nonce = param.GetIV(); _initialAssociatedText = null; keyParam = (KeyParameter)param.Parameters; } else { throw new ArgumentException("invalid parameters passed to ChaCha20Poly1305"); } if (_nonce == null || _nonce.Length < 1) { throw new ArgumentException("IV must be at least 1 byte"); } // Geneate the key ChaCha7539Engine tmpCypher = new ChaCha7539Engine(); byte[] zero = new byte[32]; byte[] polyKey = new byte[32]; ParametersWithIV tmpKey = new ParametersWithIV(keyParam, _nonce); tmpCypher.Init(true, tmpKey); tmpCypher.ProcessBytes(zero, 0, zero.Length, polyKey, 0); _poly = new Poly1305(); KeyParameter tmpKey2 = new KeyParameter(polyKey); _poly.Init(tmpKey2); _chacha20 = new ChaChaX(); _chacha20.Init(forEncryption, tmpKey); InitCipher(); }
/// <exception cref="IOException"></exception> public Chacha20Poly1305(TlsContext context) { if (!TlsUtilities.IsTlsV12(context)) throw new TlsFatalAlert(AlertDescription.internal_error); this.context = context; int cipherKeySize = 32; // TODO SecurityParameters.fixed_iv_length int fixed_iv_length = 12; // TODO SecurityParameters.record_iv_length = 0 int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length); byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size); int offset = 0; KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize); offset += cipherKeySize; KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize); offset += cipherKeySize; byte[] client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length); offset += fixed_iv_length; byte[] server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length); offset += fixed_iv_length; if (offset != key_block_size) throw new TlsFatalAlert(AlertDescription.internal_error); this.encryptCipher = new ChaCha7539Engine(); this.decryptCipher = new ChaCha7539Engine(); KeyParameter encryptKey, decryptKey; if (context.IsServer) { encryptKey = server_write_key; decryptKey = client_write_key; this.encryptIV = server_write_IV; this.decryptIV = client_write_IV; } else { encryptKey = client_write_key; decryptKey = server_write_key; this.encryptIV = client_write_IV; this.decryptIV = server_write_IV; } this.encryptCipher.Init(true, new ParametersWithIV(encryptKey, encryptIV)); this.decryptCipher.Init(false, new ParametersWithIV(decryptKey, decryptIV)); }
public byte[] Decrypt(byte[] cipher, byte[] key, byte[] iv, byte[] aad = null, byte[] associated = null) { if (key.Length * 8 != this.KeySize) { throw new InvalidOperationException($"the given key has invalid size {key.Length * 8}, expect {this.KeySize}"); } if (iv.Length != 12) { throw new InvalidOperationException($"chacha20 requires 96 bits IV, got {iv.Length * 8}"); } if (cipher.Length <= 16) { throw new ArgumentException($"incorrect argument [cipher] size"); } // split cipher and mac var cipherText = cipher.Take(cipher.Length - 16).ToArray(); var macText = cipher.Skip(cipher.Length - 16).ToArray(); var engine = new Engines.ChaCha7539Engine(); engine.Init(false, new Parameters.ParametersWithIV(new Parameters.KeyParameter(key), iv)); // calculate mac key var mackeyBlock = new byte[64]; engine.ProcessBytes(mackeyBlock, 0, mackeyBlock.Length, mackeyBlock, 0); var mackey = mackeyBlock.Take(32).ToArray(); // calculate mac var poly = new Macs.Poly1305(); poly.Init(new Parameters.KeyParameter(mackey)); PolyUpdateMacText(poly, aad); PolyUpdateMacText(poly, cipherText); PolyUpdateMacLength(poly, aad.Length); PolyUpdateMacLength(poly, cipherText.Length); var myMac = PolyDoFinal(poly); if (!Utils.BytesEqual(myMac, macText)) { throw new ArgumentException("bad record mac"); } // decrypt var plain = new byte[cipherText.Length]; engine.ProcessBytes(cipherText, 0, cipherText.Length, plain, 0); return(plain); }
public byte[] Encrypt(byte[] plain, byte[] key, byte[] iv, byte[] aad = null, byte[] associated = null) { if (key.Length * 8 != this.KeySize) { throw new InvalidOperationException($"the given key has invalid size {key.Length * 8}, expect {this.KeySize}"); } if (iv.Length != 12) { throw new InvalidOperationException($"chacha20 requires 96 bits IV, got {iv.Length * 8}"); } var engine = new Engines.ChaCha7539Engine(); engine.Init(true, new Parameters.ParametersWithIV(new Parameters.KeyParameter(key), iv)); // calculate mac key var mackeyBlock = new byte[64]; engine.ProcessBytes(mackeyBlock, 0, mackeyBlock.Length, mackeyBlock, 0); var mackey = mackeyBlock.Take(32).ToArray(); // encrypt var cipher = new byte[plain.Length]; engine.ProcessBytes(plain, 0, plain.Length, cipher, 0); // calculate mac var poly = new Macs.Poly1305(); poly.Init(new Parameters.KeyParameter(mackey)); PolyUpdateMacText(poly, aad); PolyUpdateMacText(poly, cipher); PolyUpdateMacLength(poly, aad.Length); PolyUpdateMacLength(poly, cipher.Length); var myMac = PolyDoFinal(poly); var cipherBlock = new byte[cipher.Length + myMac.Length]; Buffer.BlockCopy(cipher, 0, cipherBlock, 0, cipher.Length); Buffer.BlockCopy(myMac, 0, cipherBlock, cipher.Length, myMac.Length); return(cipherBlock); }