public static void HSalsa20(byte[] output, int outputOffset, byte[] key, int keyOffset, byte[] nonce, int nonceOffset) { Array16 <uint> state; state.x0 = SalsaConst0; state.x1 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 0); state.x2 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 4); state.x3 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 8); state.x4 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 12); state.x5 = SalsaConst1; state.x6 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 0); state.x7 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 4); state.x8 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 8); state.x9 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 12); state.x10 = SalsaConst2; state.x11 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 16); state.x12 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 20); state.x13 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 24); state.x14 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 28); state.x15 = SalsaConst3; SalsaCore.HSalsa(out state, ref state, 20); ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 0, state.x0); ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 4, state.x5); ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 8, state.x10); ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 12, state.x15); ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 16, state.x6); ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 20, state.x7); ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 24, state.x8); ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 28, state.x9); }
private static void HSalsa20Core(int size) { byte[] input = new byte[64] { 6, 124, 83, 146, 38, 191, 9, 50, 4, 161, 47, 222, 122, 182, 223, 185, 75, 27, 0, 216, 16, 122, 7, 89, 162, 104, 101, 147, 213, 21, 54, 95, 225, 253, 139, 176, 105, 132, 23, 116, 76, 41, 176, 207, 221, 34, 157, 108, 94, 94, 99, 52, 90, 117, 91, 220, 146, 190, 239, 143, 196, 176, 130, 186 }; Array16 <UInt32> state; ByteIntegerConverter.Array16LoadLittleEndian32(out state, input, 0); for (int i = 0; i < (size + 63) / 64; i++) { SalsaCore.HSalsa(out state, ref state, 20); } }
public void DoubleRound1() { Array16 <UInt32> input = new Array16 <uint>(); input.x0 = 1; Array16 <UInt32> output; UInt32[] expected = new UInt32[16] { 0x8186a22d, 0x0040a284, 0x82479210, 0x06929051, 0x08000090, 0x02402200, 0x00004000, 0x00800000, 0x00010200, 0x20400000, 0x08008104, 0x00000000, 0x20500000, 0xa0000040, 0x0008180a, 0x612a8020 }; SalsaCore.HSalsa(out output, ref input, 2); Assert.IsTrue(ToArray(output).SequenceEqual(expected)); }
private static void PrepareInternalKey(out Array16 <UInt32> internalKey, byte[] key, int keyOffset, byte[] nonce, int nonceOffset) { internalKey.x0 = Salsa20.SalsaConst0; internalKey.x1 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 0); internalKey.x2 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 4); internalKey.x3 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 8); internalKey.x4 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 12); internalKey.x5 = Salsa20.SalsaConst1; internalKey.x6 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 0); internalKey.x7 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 4); internalKey.x8 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 8); internalKey.x9 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 12); internalKey.x10 = Salsa20.SalsaConst2; internalKey.x11 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 16); internalKey.x12 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 20); internalKey.x13 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 24); internalKey.x14 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 28); internalKey.x15 = Salsa20.SalsaConst3; SalsaCore.HSalsa(out internalKey, ref internalKey, 20); //key internalKey.x1 = internalKey.x0; internalKey.x2 = internalKey.x5; internalKey.x3 = internalKey.x10; internalKey.x4 = internalKey.x15; internalKey.x11 = internalKey.x6; internalKey.x12 = internalKey.x7; internalKey.x13 = internalKey.x8; internalKey.x14 = internalKey.x9; //const internalKey.x0 = Salsa20.SalsaConst0; internalKey.x5 = Salsa20.SalsaConst1; internalKey.x10 = Salsa20.SalsaConst2; internalKey.x15 = Salsa20.SalsaConst3; //nonce internalKey.x6 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 16); internalKey.x7 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 20); //offset internalKey.x8 = 0; internalKey.x9 = 0; }
private static void EncryptInternal(byte[] ciphertext, int ciphertextOffset, byte[] message, int messageOffset, int messageLength, byte[] key, int keyOffset, byte[] nonce, int nonceOffset) { Array16 <uint> internalKey; PrepareInternalKey(out internalKey, key, keyOffset, nonce, nonceOffset); Array16 <uint> temp; byte[] tempBytes = new byte[64]; //todo: remove allocation Array8 <uint> poly1305Key; // first iteration { SalsaCore.HSalsa(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 < count; i++) { ciphertext[16 + ciphertextOffset + i] = (byte)(message[messageOffset + i] ^ tempBytes[i]); } } // later iterations int blockOffset = 32; while (blockOffset < messageLength) { internalKey.x8++; SalsaCore.HSalsa(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[16 + ciphertextOffset + blockOffset + i] = (byte)(message[messageOffset + blockOffset + i] ^ tempBytes[i]); } blockOffset += 64; } // compute MAC Poly1305Donna.poly1305_auth(ciphertext, ciphertextOffset, ciphertext, ciphertextOffset + 16, messageLength, ref poly1305Key); }
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 <uint> internalKey; PrepareInternalKey(out internalKey, key, keyOffset, nonce, nonceOffset); Array16 <uint> temp; byte[] tempBytes = new byte[64]; //todo: remove allocation // first iteration { SalsaCore.HSalsa(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); 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.HSalsa(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); }