private static bool DecryptInternal(byte[] plaintext, int plaintextOffset, byte[] ciphertext, int ciphertextOffset, int ciphertextLength, byte[] key, int keyOffset, byte[] nonce, int nonceOffset) { var plaintextLength = ciphertextLength - MacSizeInBytes; PrepareInternalKey(out Array16 <uint> internalKey, key, keyOffset, nonce, nonceOffset); Array16 <uint> temp; var tempBytes = new byte[64]; // TODO: remove allocation // first iteration { SalsaCore.Salsa(out temp, ref internalKey, 20); //first half is for Poly1305 Array8 <uint> 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); var count = Math.Min(32, plaintextLength); for (var i = 0; i < count; i++) { plaintext[plaintextOffset + i] = (byte)(ciphertext[MacSizeInBytes + ciphertextOffset + i] ^ tempBytes[i]); } } // later iterations var blockOffset = 32; while (blockOffset < plaintextLength) { internalKey.x8++; SalsaCore.Salsa(out temp, ref internalKey, 20); ByteIntegerConverter.Array16StoreLittleEndian32(tempBytes, 0, ref temp); var count = Math.Min(64, plaintextLength - blockOffset); for (var i = 0; i < count; i++) { plaintext[plaintextOffset + blockOffset + i] = (byte)(ciphertext[16 + ciphertextOffset + blockOffset + i] ^ tempBytes[i]); } blockOffset += 64; } return(true); }
public void Update(byte[] data, int offset, int count) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } if (data.Length - offset < count) { throw new ArgumentException("Requires offset + count <= data.Length"); } Array16 <ulong> block; var 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 = System.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[] PublicKeyFromSeed(byte[] privateKeySeed) { KeyPairFromSeed(out byte[] publicKey, out byte[] privateKey, privateKeySeed); CryptoBytes.Wipe(privateKey); return(publicKey); }