public void Salsa20_1000000() { 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 }; byte[] expectedOutput = new byte[64] { 8, 18, 38, 199, 119, 76, 215, 67, 173, 127, 144, 162, 103, 212, 176, 217, 192, 19, 233, 33, 159, 197, 154, 160, 128, 243, 219, 65, 171, 136, 135, 225, 123, 11, 68, 86, 237, 82, 20, 155, 133, 189, 9, 83, 167, 116, 194, 78, 122, 127, 195, 185, 185, 204, 188, 90, 245, 9, 183, 248, 226, 85, 245, 104 }; byte[] actualOutput = new byte[64]; Array16 <UInt32> state; ByteIntegerConverter.Array16LoadLittleEndian32(out state, input, 0); for (int i = 0; i < 1000000; i++) { SalsaCore.Salsa(out state, ref state, 20); } ByteIntegerConverter.Array16StoreLittleEndian32(actualOutput, 0, ref state); TestHelpers.AssertEqualBytes(expectedOutput, actualOutput); }
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! }
private static void EncryptInternal(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; var tempBytes = new byte[64];//todo: remove allocation Array8 <UInt32> 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 < count; i++) { ciphertext[16 + ciphertextOffset + i] = (byte)(message[messageOffset + i] ^ tempBytes[i]); } } // later iterations int blockOffset = 32; 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[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); }
public void Zero() { Array16 <UInt32> input = new Array16 <uint>(); Array16 <UInt32> output; UInt32[] expected = new UInt32[16]; SalsaCore.Salsa(out output, ref input, 20); Assert.IsTrue(ToArray(output).SequenceEqual(expected)); }
public static void GetPublicKey(ArraySegment\\ publicKey, ArraySegment\\ privateKey) { if (publicKey.Array == null) throw new ArgumentNullException("publicKey.Array"); if (privateKey.Array == null) throw new ArgumentNullException("privateKey.Array"); if (publicKey.Count != PublicKeySizeInBytes) throw new ArgumentException("privateKey.Count must be 32"); if (privateKey.Count != PrivateKeySizeInBytes) throw new ArgumentException("privateKey.Count must be 32"); // hack: abusing publicKey as temporary storage // todo: remove hack for (int i = 0; i \\ salsaState; salsaState.x0 = c0; salsaState.x1 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 0); salsaState.x2 = 0; salsaState.x3 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 4); salsaState.x4 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 8); salsaState.x5 = c1; salsaState.x6 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 12); salsaState.x7 = 0; salsaState.x8 = 0; salsaState.x9 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 16); salsaState.x10 = c2; salsaState.x11 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 20); salsaState.x12 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 24); salsaState.x13 = 0; salsaState.x14 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 28); salsaState.x15 = c3; SalsaCore.Salsa(out salsaState, ref salsaState, 20); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 0, salsaState.x0); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 4, salsaState.x1); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 8, salsaState.x2); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 12, salsaState.x3); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 16, salsaState.x4); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 20, salsaState.x5); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 24, salsaState.x6); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 28, salsaState.x7); }
// hashes like the Curve25519 paper says internal static void KeyExchangeOutputHashCurve25519Paper(byte[] sharedKey, int offset) { //c = Curve25519output const UInt32 c0 = 'C' | 'u' << 8 | 'r' << 16 | (UInt32)'v' << 24; const UInt32 c1 = 'e' | '2' << 8 | '5' << 16 | (UInt32)'5' << 24; const UInt32 c2 = '1' | '9' << 8 | 'o' << 16 | (UInt32)'u' << 24; const UInt32 c3 = 't' | 'p' << 8 | 'u' << 16 | (UInt32)'t' << 24; Array16 <UInt32> salsaState; salsaState.x0 = c0; salsaState.x1 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 0); salsaState.x2 = 0; salsaState.x3 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 4); salsaState.x4 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 8); salsaState.x5 = c1; salsaState.x6 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 12); salsaState.x7 = 0; salsaState.x8 = 0; salsaState.x9 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 16); salsaState.x10 = c2; salsaState.x11 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 20); salsaState.x12 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 24); salsaState.x13 = 0; salsaState.x14 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 28); salsaState.x15 = c3; SalsaCore.Salsa(out salsaState, ref salsaState, 20); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 0, salsaState.x0); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 4, salsaState.x1); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 8, salsaState.x2); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 12, salsaState.x3); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 16, salsaState.x4); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 20, salsaState.x5); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 24, salsaState.x6); ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 28, salsaState.x7); }
public void Salsa20() { byte[] input = new byte[64] { 211, 159, 13, 115, 76, 55, 82, 183, 3, 117, 222, 37, 191, 187, 234, 136, 49, 237, 179, 48, 1, 106, 178, 219, 175, 199, 166, 48, 86, 16, 179, 207, 31, 240, 32, 63, 15, 83, 93, 161, 116, 147, 48, 113, 238, 55, 204, 36, 79, 201, 235, 79, 3, 81, 156, 47, 203, 26, 244, 243, 88, 118, 104, 54 }; byte[] expectedOutput = new byte[64] { 109, 42, 178, 168, 156, 240, 248, 238, 168, 196, 190, 203, 26, 110, 170, 154, 29, 29, 150, 26, 150, 30, 235, 249, 190, 163, 251, 48, 69, 144, 51, 57, 118, 40, 152, 157, 180, 57, 27, 94, 107, 42, 236, 35, 27, 111, 114, 114, 219, 236, 232, 135, 111, 155, 110, 18, 24, 232, 95, 158, 179, 19, 48, 202 }; byte[] actualOutput = new byte[64]; Array16 <UInt32> inputState; Array16 <UInt32> outputState; ByteIntegerConverter.Array16LoadLittleEndian32(out inputState, input, 0); SalsaCore.Salsa(out outputState, ref inputState, 20); ByteIntegerConverter.Array16StoreLittleEndian32(actualOutput, 0, ref outputState); TestHelpers.AssertEqualBytes(expectedOutput, actualOutput); }
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); }
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 \