/// <summary> /// Finalizes SHA-512 hashing /// </summary> /// <param name="output">Output buffer</param> public void Finalize(ArraySegment <byte> output) { Contract.Requires <ArgumentNullException>(output.Array != null); Contract.Requires <ArgumentException>(output.Count == 64); Update(_padding, 0, _padding.Length); Array16 <ulong> block; ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer, 0); CryptoBytes.InternalWipe(_buffer, 0, _buffer.Length); int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); if (bytesInBuffer > BlockSize - 16) { Sha512Internal.Core(out _state, ref _state, ref block); block = default(Array16 <ulong>); } block.x15 = (_totalBytes - 1) * 8; Sha512Internal.Core(out _state, ref _state, ref block); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 0, _state.x0); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 8, _state.x1); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 16, _state.x2); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 24, _state.x3); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 32, _state.x4); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 40, _state.x5); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 48, _state.x6); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 56, _state.x7); _state = default(Array8 <ulong>); }
public override bool Verify(byte[] signature, byte[] message, byte[] key) { if (signature == null) { throw new ArgumentNullException("signature"); } if (message == null) { throw new ArgumentNullException("message"); } if (key == null) { throw new ArgumentNullException("key"); } if (signature.Length != 16) { throw new ArgumentException("Invalid signature size", "signature"); } if (key.Length != 32) { throw new ArgumentException("Invalid key size", "key"); } var tempBytes = new byte[16];//todo: remove allocation Array8 \ \ internalKey; ByteIntegerConverter.Array8LoadLittleEndian32(out internalKey, key, 0); Poly1305Donna.poly1305_auth(tempBytes, 0, message, 0, message.Length, ref internalKey); return(CryptoBytes.ConstantTimeEquals(tempBytes, signature)); }
public override bool Verify(ArraySegment \ \ signature, ArraySegment \ \ message, ArraySegment \ \ key) { if (signature.Array == null) { throw new ArgumentNullException("signature.Array"); } if (message.Array == null) { throw new ArgumentNullException("message.Array"); } if (key.Array == null) { throw new ArgumentNullException("key.Array"); } if (key.Count != 32) { throw new ArgumentException("Invalid key size", "key"); } if (signature.Count != 16) { throw new ArgumentException("Invalid signature size", "signature"); } var tempBytes = new byte[16];//todo: remove allocation Array8 \ \ internalKey; ByteIntegerConverter.Array8LoadLittleEndian32(out internalKey, key.Array, key.Offset); Poly1305Donna.poly1305_auth(tempBytes, 0, message.Array, message.Offset, message.Count, ref internalKey); return(CryptoBytes.ConstantTimeEquals(new ArraySegment \ \ (tempBytes), signature)); }
public void Finish(ArraySegment\\ output) { if (output.Array == null) throw new ArgumentNullException("output.Array"); if (output.Count != 64) throw new ArgumentException("output.Count must be 64"); Update(_padding, 0, _padding.Length); Array16\\ block; ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer, 0); CryptoBytes.InternalWipe(_buffer, 0, _buffer.Length); int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); if (bytesInBuffer \>\ BlockSize - 16) { Sha512Internal.Core(out _state, ref _state, ref block); block = default(Array16\\); } block.x15 = (_totalBytes - 1) * 8; Sha512Internal.Core(out _state, ref _state, ref block); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 0, _state.x0); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 8, _state.x1); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 16, _state.x2); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 24, _state.x3); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 32, _state.x4); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 40, _state.x5); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 48, _state.x6); ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 56, _state.x7); _state = default(Array8\\); }
private static void ProcessInternal(byte[] ciphertext, int ciphertextOffset, byte[] message, int messageOffset, int messageLength, byte[] key, int keyOffset, byte[] nonce, int nonceOffset) { Array16 <UInt32> internalKey; PrepareInternalKey(out internalKey, key, keyOffset, nonce, nonceOffset); Array16 <UInt32> temp; byte[] tempBytes = new byte[64];//todo: remove allocation int blockOffset = 0; while (blockOffset < messageLength) { //internalKey.x8++; SalsaCore.Salsa(out temp, ref internalKey, 20); ByteIntegerConverter.Array16StoreLittleEndian32(tempBytes, 0, ref temp); int count = Math.Min(64, messageLength - blockOffset); for (int i = 0; i < count; i++) { ciphertext[ciphertextOffset + blockOffset + i] = (byte)(message[messageOffset + blockOffset + i] ^ tempBytes[i]); } blockOffset += 64; internalKey.x8++; } CryptoBytes.Wipe(tempBytes); // DON'T LEAK! }
public static void KeyExchange(Span <byte> sharedKey, ReadOnlySpan <byte> publicKey, ReadOnlySpan <byte> privateKey) { if (sharedKey.Length != 32) { throw new ArgumentException("sharedKey.Count != 32"); } if (publicKey.Length != 32) { throw new ArgumentException("publicKey.Count != 32"); } if (privateKey.Length != 64) { throw new ArgumentException("privateKey.Count != 64"); } FieldOperations.fe_frombytes(out var edwardsY, publicKey); FieldOperations.fe_1(out var edwardsZ); MontgomeryCurve25519.EdwardsToMontgomeryX(out var montgomeryX, ref edwardsY, ref edwardsZ); Span <byte> h = stackalloc byte[64]; Sha512.Hash(privateKey.Slice(0, 32), h); ScalarOperations.sc_clamp(h); MontgomeryOperations.scalarmult(out var sharedMontgomeryX, h, in montgomeryX); CryptoBytes.Wipe(h); FieldOperations.fe_tobytes(sharedKey, in sharedMontgomeryX); }
public static byte[] ExpandedPrivateKeyFromSeed(byte[] privateKeySeed) { byte[] privateKey; byte[] publicKey; KeyPairFromSeed(out publicKey, out privateKey, privateKeySeed); CryptoBytes.Wipe(publicKey); return(privateKey); }
public void Update(byte[] data, int offset, int count) { if (data == null) { throw new ArgumentNullException("data"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (data.Length - offset < count) { throw new ArgumentException("Requires offset + count <= data.Length"); } Array16 <ulong> block; int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); _totalBytes += (uint)count; if (_totalBytes >= ulong.MaxValue / 8) { throw new InvalidOperationException("Too much data"); } // Fill existing buffer if (bytesInBuffer != 0) { var toCopy = Math.Min(BlockSize - bytesInBuffer, count); Buffer.BlockCopy(data, offset, _buffer, bytesInBuffer, toCopy); offset += toCopy; count -= toCopy; bytesInBuffer += toCopy; if (bytesInBuffer == BlockSize) { ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer, 0); Sha512Internal.Core(out _state, ref _state, ref block); CryptoBytes.InternalWipe(_buffer, 0, _buffer.Length); bytesInBuffer = 0; } } // Hash complete blocks without copying while (count >= BlockSize) { ByteIntegerConverter.Array16LoadBigEndian64(out block, data, offset); Sha512Internal.Core(out _state, ref _state, ref block); offset += BlockSize; count -= BlockSize; } // Copy remainder into buffer if (count > 0) { Buffer.BlockCopy(data, offset, _buffer, bytesInBuffer, count); } }
public static byte[] ExpandedPrivateKeyFromSeed(ReadOnlySpan <byte> privateKeySeed) { Span <byte> publicKey = stackalloc byte[PublicKeySizeInBytes]; var privateKey = new byte[ExpandedPrivateKeySizeInBytes]; KeyPairFromSeed(publicKey, privateKey, privateKeySeed); CryptoBytes.Wipe(publicKey); return(privateKey); }
/// <summary> /// Calculate public key from private key seed /// </summary> /// <param name="privateKeySeed">Private key seed value</param> /// <returns></returns> public static byte[] PublicKeyFromSeed(byte[] privateKeySeed) { Contract.Requires <ArgumentNullException>(privateKeySeed != null); Contract.Requires <ArgumentException>(privateKeySeed.Length == PrivateKeySeedSize); byte[] privateKey; byte[] publicKey; KeyPairFromSeed(out publicKey, out privateKey, privateKeySeed); CryptoBytes.Wipe(privateKey); return(publicKey); }
public void Finish(Span <byte> output) { if (output.Length != 64) { throw new ArgumentException("output.Count must be 64"); } Update(_padding); Array16 <ulong> block; ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer); CryptoBytes.Wipe(_buffer, 0, _buffer.Length); int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); if (bytesInBuffer > BlockSize - 16) { Sha512Internal.Core(out _state, in _state, in block); block = default; } block = new Array16 <ulong>( block.x0, block.x1, block.x2, block.x3, block.x4, block.x5, block.x6, block.x7, block.x8, block.x9, block.x10, block.x11, block.x12, block.x13, block.x14, (_totalBytes - 1) * 8); Sha512Internal.Core(out _state, in _state, in block); BinaryPrimitives.WriteUInt64BigEndian(output.Slice(0), _state.x0); BinaryPrimitives.WriteUInt64BigEndian(output.Slice(8), _state.x1); BinaryPrimitives.WriteUInt64BigEndian(output.Slice(16), _state.x2); BinaryPrimitives.WriteUInt64BigEndian(output.Slice(24), _state.x3); BinaryPrimitives.WriteUInt64BigEndian(output.Slice(32), _state.x4); BinaryPrimitives.WriteUInt64BigEndian(output.Slice(40), _state.x5); BinaryPrimitives.WriteUInt64BigEndian(output.Slice(48), _state.x6); BinaryPrimitives.WriteUInt64BigEndian(output.Slice(56), _state.x7); _state = default; }
public static void KeyExchange(ArraySegment <byte> sharedKey, ArraySegment <byte> publicKey, ArraySegment <byte> privateKey) { if (sharedKey.Array == null) { throw new ArgumentNullException("sharedKey.Array"); } if (publicKey.Array == null) { throw new ArgumentNullException("publicKey.Array"); } if (privateKey.Array == null) { throw new ArgumentNullException("privateKey"); } if (sharedKey.Count != 32) { throw new ArgumentException("sharedKey.Count != 32"); } if (publicKey.Count != 32) { throw new ArgumentException("publicKey.Count != 32"); } if (privateKey.Count != 64) { throw new ArgumentException("privateKey.Count != 64"); } FieldElement montgomeryX, edwardsY, edwardsZ, sharedMontgomeryX; FieldOperations.fe_frombytes(out edwardsY, publicKey.Array, publicKey.Offset); FieldOperations.fe_1(out edwardsZ); MontgomeryCurve25519.EdwardsToMontgomeryX(out montgomeryX, ref edwardsY, ref edwardsZ); var blake2bConfig = new Blake2BConfig { OutputSizeInBytes = 64 }; var hasher = Blake2B.Create(blake2bConfig); hasher.Update(privateKey.Array, privateKey.Offset, 32); byte[] h = hasher.Finish(); //byte[] h = Sha512.Hash(privateKey.Array, privateKey.Offset, 32);//ToDo: Remove alloc ScalarOperations.sc_clamp(h, 0); MontgomeryOperations.scalarmult(out sharedMontgomeryX, h, 0, ref montgomeryX); CryptoBytes.Wipe(h); FieldOperations.fe_tobytes(sharedKey.Array, sharedKey.Offset, ref sharedMontgomeryX); MontgomeryCurve25519.KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset); }
public static void crypto_sign2( byte[] sig, byte[] m, byte[] sk, int keylen) { byte[] privHash = new byte[64]; byte[] seededHash = new byte[64]; byte[] result = new byte[64]; GroupElementP3 R = new GroupElementP3(); var hasher = new KeccakDigest(512); { var reversedPrivateKey = new byte[keylen]; Array.Copy(sk, 0, reversedPrivateKey, 0, keylen); Array.Reverse(reversedPrivateKey); hasher.BlockUpdate(reversedPrivateKey, 0, keylen); hasher.DoFinal(privHash, 0); ScalarOperations.sc_clamp(privHash, 0); hasher.Reset(); hasher.BlockUpdate(privHash, 32, 32); hasher.BlockUpdate(m, 0, m.Length); hasher.DoFinal(seededHash, 0); ScalarOperations.sc_reduce(seededHash); GroupOperations.ge_scalarmult_base(out R, seededHash, 0); GroupOperations.ge_p3_tobytes(sig, 0, ref R); hasher.Reset(); hasher.BlockUpdate(sig, 0, 32); hasher.BlockUpdate(sk, keylen, 32); hasher.BlockUpdate(m, 0, m.Length); hasher.DoFinal(result, 0); ScalarOperations.sc_reduce(result); var s = new byte[32];//todo: remove allocation Array.Copy(sig, 32, s, 0, 32); ScalarOperations.sc_muladd(s, result, privHash, seededHash); Array.Copy(s, 0, sig, 32, 32); CryptoBytes.Wipe(s); } }
/// <summary> /// Updates internal state with data from the provided array. /// </summary> /// <param name="data">Array of bytes</param> /// <param name="index">Offset of byte sequence</param> /// <param name="length">Sequence length</param> public void Update(byte[] data, int index, int length) { Contract.Requires <ArgumentNullException>(data != null); Contract.Requires <ArgumentOutOfRangeException>(index >= 0 && length >= 0); Contract.Requires <ArgumentException>((index + length) <= data.Length); Array16 <ulong> block; int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); _totalBytes += (uint)length; if (_totalBytes >= ulong.MaxValue / 8) { throw new InvalidOperationException("Too much data"); } // Fill existing buffer if (bytesInBuffer != 0) { var toCopy = Math.Min(BlockSize - bytesInBuffer, length); Buffer.BlockCopy(data, index, _buffer, bytesInBuffer, toCopy); index += toCopy; length -= toCopy; bytesInBuffer += toCopy; if (bytesInBuffer == BlockSize) { ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer, 0); Sha512Internal.Core(out _state, ref _state, ref block); CryptoBytes.InternalWipe(_buffer, 0, _buffer.Length); bytesInBuffer = 0; } } // Hash complete blocks without copying while (length >= BlockSize) { ByteIntegerConverter.Array16LoadBigEndian64(out block, data, index); Sha512Internal.Core(out _state, ref _state, ref block); index += BlockSize; length -= BlockSize; } // Copy remainder into buffer if (length > 0) { Buffer.BlockCopy(data, index, _buffer, bytesInBuffer, length); } }
public static void KeyExchange(ArraySegment <byte> sharedKey, ArraySegment <byte> publicKey, ArraySegment <byte> privateKey) { if (sharedKey.Array == null) { throw new ArgumentNullException("sharedKey.Array"); } if (publicKey.Array == null) { throw new ArgumentNullException("publicKey.Array"); } if (privateKey.Array == null) { throw new ArgumentNullException("privateKey"); } if (sharedKey.Count != 32) { throw new ArgumentException("sharedKey.Count != 32"); } if (publicKey.Count != 32) { throw new ArgumentException("publicKey.Count != 32"); } if (privateKey.Count != 64) { throw new ArgumentException("privateKey.Count != 64"); } FieldElement montgomeryX, edwardsY, edwardsZ, sharedMontgomeryX; FieldOperations.fe_frombytes(out edwardsY, publicKey.Array, publicKey.Offset); FieldOperations.fe_1(out edwardsZ); MontgomeryCurve25519.EdwardsToMontgomeryX(out montgomeryX, ref edwardsY, ref edwardsZ); var hasher = Blake2Fast.Blake2b.CreateIncrementalHasher(64); hasher.Update(new ArraySegment <byte>(privateKey.Array, privateKey.Offset, 32)); byte[] h = hasher.Finish(); ScalarOperations.sc_clamp(h, 0); MontgomeryOperations.scalarmult(out sharedMontgomeryX, h, 0, ref montgomeryX); CryptoBytes.Wipe(h); FieldOperations.fe_tobytes(sharedKey.Array, sharedKey.Offset, ref sharedMontgomeryX); MontgomeryCurve25519.KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset); }
public void Update(ReadOnlySpan <byte> data) { Array16 <ulong> block; int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); _totalBytes += (uint)data.Length; var bufferSpan = _buffer.AsSpan(); if (_totalBytes >= ulong.MaxValue / 8) { throw new InvalidOperationException("Too much data"); } // Fill existing buffer if (bytesInBuffer != 0) { var toCopy = Math.Min(BlockSize - bytesInBuffer, data.Length); data.Slice(0, toCopy).CopyTo(bufferSpan.Slice(bytesInBuffer)); data = data.Slice(toCopy); bytesInBuffer += toCopy; if (bytesInBuffer == BlockSize) { ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer); Sha512Internal.Core(out _state, in _state, in block); CryptoBytes.Wipe(_buffer, 0, _buffer.Length); bytesInBuffer = 0; } } // Hash complete blocks without copying while (data.Length >= BlockSize) { ByteIntegerConverter.Array16LoadBigEndian64(out block, data); Sha512Internal.Core(out _state, in _state, in block); data = data.Slice(BlockSize); } // Copy remainder into buffer if (data.Length > 0) { data.CopyTo(bufferSpan.Slice(bytesInBuffer)); } }
public static void KeyExchange(ArraySegment \ \ sharedKey, ArraySegment \ \ publicKey, ArraySegment \ \ privateKey) { if (sharedKey.Array == null) { throw new ArgumentNullException("sharedKey.Array"); } if (publicKey.Array == null) { throw new ArgumentNullException("publicKey.Array"); } if (privateKey.Array == null) { throw new ArgumentNullException("privateKey"); } if (sharedKey.Count != 32) { throw new ArgumentException("sharedKey.Count != 32"); } if (publicKey.Count != 32) { throw new ArgumentException("publicKey.Count != 32"); } if (privateKey.Count != 64) { throw new ArgumentException("privateKey.Count != 64"); } FieldElement montgomeryX, edwardsY, edwardsZ, sharedMontgomeryX; FieldOperations.fe_frombytes(out edwardsY, publicKey.Array, publicKey.Offset); FieldOperations.fe_1(out edwardsZ); MontgomeryCurve25519.EdwardsToMontgomeryX(out montgomeryX, ref edwardsY, ref edwardsZ); byte[] h = Sha512.Hash(privateKey.Array, privateKey.Offset, 32);//ToDo: Remove alloc ScalarOperations.sc_clamp(h, 0); MontgomeryOperations.scalarmult(out sharedMontgomeryX, h, 0, ref montgomeryX); CryptoBytes.Wipe(h); FieldOperations.fe_tobytes(sharedKey.Array, sharedKey.Offset, ref sharedMontgomeryX); MontgomeryCurve25519.KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset); }
private static bool DecryptInternal(byte[] plaintext, int plaintextOffset, byte[] ciphertext, int ciphertextOffset, int ciphertextLength, byte[] key, int keyOffset, byte[] nonce, int nonceOffset) { int plaintextLength = ciphertextLength - MacSizeInBytes; Array16\\ internalKey; PrepareInternalKey(out internalKey, key, keyOffset, nonce, nonceOffset); Array16\\ temp; var tempBytes = new byte[64];//todo: remove allocation // first iteration { SalsaCore.Salsa(out temp, ref internalKey, 20); //first half is for Poly1305 Array8\\ poly1305Key; poly1305Key.x0 = temp.x0; poly1305Key.x1 = temp.x1; poly1305Key.x2 = temp.x2; poly1305Key.x3 = temp.x3; poly1305Key.x4 = temp.x4; poly1305Key.x5 = temp.x5; poly1305Key.x6 = temp.x6; poly1305Key.x7 = temp.x7; // compute MAC Poly1305Donna.poly1305_auth(tempBytes, 0, ciphertext, ciphertextOffset + 16, plaintextLength, ref poly1305Key); if (!CryptoBytes.ConstantTimeEquals(tempBytes, 0, ciphertext, ciphertextOffset, MacSizeInBytes)) { Array.Clear(plaintext, plaintextOffset, plaintextLength); return false; } // rest for the message ByteIntegerConverter.StoreLittleEndian32(tempBytes, 0, temp.x8); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 4, temp.x9); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 8, temp.x10); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 12, temp.x11); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 16, temp.x12); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 20, temp.x13); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 24, temp.x14); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 28, temp.x15); int count = Math.Min(32, plaintextLength); for (int i = 0; i \\ internalKey; PrepareInternalKey(out internalKey, key, keyOffset, nonce, nonceOffset); Array16\\ temp; var tempBytes = new byte[64];//todo: remove allocation Array8\\ poly1305Key; // first iteration { SalsaCore.Salsa(out temp, ref internalKey, 20); //first half is for Poly1305 poly1305Key.x0 = temp.x0; poly1305Key.x1 = temp.x1; poly1305Key.x2 = temp.x2; poly1305Key.x3 = temp.x3; poly1305Key.x4 = temp.x4; poly1305Key.x5 = temp.x5; poly1305Key.x6 = temp.x6; poly1305Key.x7 = temp.x7; // second half for the message ByteIntegerConverter.StoreLittleEndian32(tempBytes, 0, temp.x8); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 4, temp.x9); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 8, temp.x10); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 12, temp.x11); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 16, temp.x12); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 20, temp.x13); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 24, temp.x14); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 28, temp.x15); int count = Math.Min(32, messageLength); for (int i = 0; i \
private static bool DecryptInternal(byte[] plaintext, int plaintextOffset, byte[] ciphertext, int ciphertextOffset, int ciphertextLength, byte[] key, int keyOffset, byte[] nonce, int nonceOffset) { int plaintextLength = ciphertextLength - MacSizeInBytes; Array16 <UInt32> internalKey; PrepareInternalKey(out internalKey, key, keyOffset, nonce, nonceOffset); Array16 <UInt32> temp; var tempBytes = new byte[64];//todo: remove allocation // first iteration { SalsaCore.Salsa(out temp, ref internalKey, 20); //first half is for Poly1305 Array8 <UInt32> poly1305Key; poly1305Key.x0 = temp.x0; poly1305Key.x1 = temp.x1; poly1305Key.x2 = temp.x2; poly1305Key.x3 = temp.x3; poly1305Key.x4 = temp.x4; poly1305Key.x5 = temp.x5; poly1305Key.x6 = temp.x6; poly1305Key.x7 = temp.x7; // compute MAC Poly1305Donna.poly1305_auth(tempBytes, 0, ciphertext, ciphertextOffset + 16, plaintextLength, ref poly1305Key); if (!CryptoBytes.ConstantTimeEquals(tempBytes, 0, ciphertext, ciphertextOffset, MacSizeInBytes)) { Array.Clear(plaintext, plaintextOffset, plaintextLength); return(false); } // rest for the message ByteIntegerConverter.StoreLittleEndian32(tempBytes, 0, temp.x8); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 4, temp.x9); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 8, temp.x10); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 12, temp.x11); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 16, temp.x12); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 20, temp.x13); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 24, temp.x14); ByteIntegerConverter.StoreLittleEndian32(tempBytes, 28, temp.x15); int count = Math.Min(32, plaintextLength); for (int i = 0; i < count; i++) { plaintext[plaintextOffset + i] = (byte)(ciphertext[MacSizeInBytes + ciphertextOffset + i] ^ tempBytes[i]); } } // later iterations int blockOffset = 32; while (blockOffset < plaintextLength) { internalKey.x8++; SalsaCore.Salsa(out temp, ref internalKey, 20); ByteIntegerConverter.Array16StoreLittleEndian32(tempBytes, 0, ref temp); int count = Math.Min(64, plaintextLength - blockOffset); for (int i = 0; i < count; i++) { plaintext[plaintextOffset + blockOffset + i] = (byte)(ciphertext[16 + ciphertextOffset + blockOffset + i] ^ tempBytes[i]); } blockOffset += 64; } return(true); }
public static byte[] PublicKeyFromSeed(byte[] privateKeySeed) { KeyPairFromSeed(out var publicKey, out var privateKey, privateKeySeed); CryptoBytes.Wipe(privateKey); return(publicKey); }