public void EciesEncryptDecryptTest() { string[] testDataSets = new string[] { "okayAESstrTest", "test2", "and another \x00 test. but this one is a sentence with \x11 weird characters." }; for (int i = 0; i < testDataSets.Length; i++) { // Generate a keypair EthereumEcdsa keypair = EthereumEcdsa.Generate(); byte[] testData = Encoding.UTF8.GetBytes(testDataSets[i]); byte[] encrypted = Ecies.Encrypt(keypair, testData, null); byte[] decrypted = Ecies.Decrypt(keypair, encrypted, null); string result = Encoding.UTF8.GetString(decrypted); Assert.Equal(testDataSets[i], result); } }
/// <summary> /// Creates authentication data to send to the responder. /// </summary> /// <param name="receiverPublicKey">The responder/receiver's public key.</param> /// <param name="nonce">The nonce to use for the authentication data. If null, new data is generated.</param> /// <returns>Returns the encrypted serialized authentication data.</returns> public byte[] CreateAuthentiation(EthereumEcdsa receiverPublicKey, byte[] nonce = null) { // Verify this is the initiator role. if (Role != RLPxSessionRole.Initiator) { throw new Exception("RLPx auth data should only be created by the initiator."); } // Verify the session state is correct. if (SessionState != RLPxSessionState.Initial) { throw new Exception("RLPx auth creation should only be performed on a new session."); } // If the nonce is null, generate a new one. nonce = nonce ?? GenerateNonce(); // Set our initiator nonce InitiatorNonce = nonce; // Set the remote public key RemotePublicKey = receiverPublicKey; // Create a new authentication message based off of our configured setting. RLPxAuthBase authMessage = null; if (UsingEIP8Authentication) { // Create our EIP8 authentication message. authMessage = new RLPxAuthEIP8() { Nonce = InitiatorNonce, Version = MAX_SUPPORTED_VERSION, }; } else { // Create our standard authentication message. authMessage = new RLPxAuthStandard() { Nonce = InitiatorNonce, }; } // Sign the authentication message authMessage.Sign(LocalPrivateKey, LocalEphemeralPrivateKey, RemotePublicKey, ChainId); // Serialize the authentication data byte[] serializedData = authMessage.Serialize(); // Encrypt the data accordingly (standard uses no shared mac data, EIP8 has 2 bytes which prefix the resulting encrypted data). if (UsingEIP8Authentication) { // Obtain two bytes of mac data by EIP8 standards (big endian 16-bit unsigned integer equal to the size of the resulting ECIES encrypted data). // We can calculate this as the amount of overhead data ECIES adds is static in size. byte[] sharedMacData = BigIntegerConverter.GetBytes(serializedData.Length + Ecies.ECIES_ADDITIONAL_OVERHEAD, 2); // Encrypt the serialized data with the shared mac data, and prefix the result with it. byte[] encryptedSerializedData = Ecies.Encrypt(RemotePublicKey, serializedData, sharedMacData); AuthData = sharedMacData.Concat(encryptedSerializedData); } else { // Encrypt it using ECIES without any shared mac data. AuthData = Ecies.Encrypt(RemotePublicKey, serializedData, null); } // Set the session state SessionState = RLPxSessionState.AuthenticationCompleted; // Return the auth data return(AuthData); }
/// <summary> /// Creates authentication acknowledgement data to send to the initiator, signalling that their authentication /// data was successfully verified, and providing the initiator with information that they have already provided /// to the responder (so they can both derive the same shared secrets). /// </summary> /// <param name="nonce">The nonce to use for the authentication data. If null, new data is generated.</param> /// <returns>Returns the encrypted serialized authentication acknowledgement data.</returns> public byte[] CreateAuthenticationAcknowledgement(byte[] nonce = null) { // Verify this is the responder role. if (Role != RLPxSessionRole.Responder) { throw new Exception("RLPx auth-ack data should only be created by the responder."); } // Verify the session state is correct. if (SessionState != RLPxSessionState.AuthenticationCompleted) { throw new Exception("RLPx auth-ack creation should only be performed on a session after auth was received/verified."); } // If the nonce is null, generate a new one. if (nonce == null) { nonce = new byte[NONCE_SIZE]; _randomNumberGenerator.GetBytes(nonce); } // Set the responder nonce ResponderNonce = nonce ?? GenerateNonce(); // If we are using EIP8 RLPxAuthAckBase authAckMessage = null; if (UsingEIP8Authentication) { // We use EIP8 authentication acknowledgement authAckMessage = new RLPxAuthAckEIP8() { EphemeralPublicKey = LocalEphemeralPrivateKey.ToPublicKeyArray(false, true), Nonce = ResponderNonce, Version = MAX_SUPPORTED_VERSION, }; } else { // We use standard authentication acknowledgement authAckMessage = new RLPxAuthAckStandard() { EphemeralPublicKey = LocalEphemeralPrivateKey.ToPublicKeyArray(false, true), Nonce = ResponderNonce, TokenFound = false, // TODO: Check for a saved session key from before, and set this accordingly. }; } // Serialize the authentication-acknowledgement data byte[] serializedData = authAckMessage.Serialize(); // Encrypt the data accordingly (standard uses no shared mac data, EIP8 has 2 bytes which prefix the resulting encrypted data). if (UsingEIP8Authentication) { // Obtain two bytes of mac data by EIP8 standards (big endian 16-bit unsigned integer equal to the size of the resulting ECIES encrypted data). // We can calculate this as the amount of overhead data ECIES adds is static in size. byte[] sharedMacData = BigIntegerConverter.GetBytes(serializedData.Length + Ecies.ECIES_ADDITIONAL_OVERHEAD, 2); // Encrypt the serialized data with the shared mac data, prefix the result with it. byte[] encryptedSerializedData = Ecies.Encrypt(RemotePublicKey, serializedData, sharedMacData); AuthAckData = sharedMacData.Concat(encryptedSerializedData); } else { // Encrypt it using ECIES without any shared mac data. AuthAckData = Ecies.Encrypt(RemotePublicKey, serializedData, null); } // Set the session state SessionState = RLPxSessionState.AcknowledgementCompleted; // Return the auth-ack data return(AuthAckData); }
public void TestCases() { const string message = "attack at dawn"; var aliceKey = PrivateKey.FromWif("L1Ejc5dAigm5XrM3mNptMEsNnHzS7s51YxU7J61ewGshZTKkbmzJ"); var bobKey = PrivateKey.FromWif("KxfxrUXSMjJQcb3JgnaaA6MqsrKQ1nBSxvhuigdKRyFiEm6BZDgG"); { var encrypted = "0339e504d6492b082da96e11e8f039796b06cd4855c101e2492a6f10f3e056a9e712c732611c6917ab5c57a1926973bc44a1586e94a783f81d05ce72518d9b0a80e2e13c7ff7d1306583f9cc7a48def5b37fbf2d5f294f128472a6e9c78dede5f5"; // encrypted broken down: // priv.pubkey 0339e504d6492b082da96e11e8f039796b06cd4855c101e2492a6f10f3e056a9e7 // ivbuf 12c732611c6917ab5c57a1926973bc44 // encrypted a1586e94a783f81d05ce72518d9b0a80 // sig e2e13c7ff7d1306583f9cc7a48def5b37fbf2d5f294f128472a6e9c78dede5f5 var alice = new Ecies { PrivateKey = aliceKey, PublicKey = bobKey.CreatePublicKey() }; var bob = new Ecies { PrivateKey = bobKey }; var ciphertext = alice.Encrypt(message); Assert.Equal(encrypted, ciphertext.ToHex()); var decryptedtext = bob.DecryptToUtf8(ciphertext); Assert.Equal(message, decryptedtext); } { var encrypted = "0339e504d6492b082da96e11e8f039796b06cd4855c101e2492a6f10f3e056a9e712c732611c6917ab5c57a1926973bc44a1586e94a783f81d05ce72518d9b0a80e2e13c7f"; // encrypted broken down: // priv.pubkey 0339e504d6492b082da96e11e8f039796b06cd4855c101e2492a6f10f3e056a9e7 // ivbuf 12c732611c6917ab5c57a1926973bc44 // encrypted a1586e94a783f81d05ce72518d9b0a80 // sig e2e13c7f var alice = new Ecies { PrivateKey = aliceKey, PublicKey = bobKey.CreatePublicKey(), ShortTag = true }; var bob = new Ecies { PrivateKey = bobKey, ShortTag = true }; var ciphertext = alice.Encrypt(message); Assert.Equal(encrypted, ciphertext.ToHex()); var decryptedtext = bob.DecryptToUtf8(ciphertext); Assert.Equal(message, decryptedtext); } { var encrypted = "12c732611c6917ab5c57a1926973bc44a1586e94a783f81d05ce72518d9b0a80e2e13c7ff7d1306583f9cc7a48def5b37fbf2d5f294f128472a6e9c78dede5f5"; // encrypted broken down: // priv.pubkey // ivbuf 12c732611c6917ab5c57a1926973bc44 // encrypted a1586e94a783f81d05ce72518d9b0a80 // sig e2e13c7ff7d1306583f9cc7a48def5b37fbf2d5f294f128472a6e9c78dede5f5 var alice = new Ecies { PrivateKey = aliceKey, PublicKey = bobKey.CreatePublicKey(), NoKey = true }; var bob = new Ecies { PrivateKey = bobKey, PublicKey = aliceKey.CreatePublicKey(), NoKey = true }; var ciphertext = alice.Encrypt(message); Assert.Equal(encrypted, ciphertext.ToHex()); var decryptedtext = bob.DecryptToUtf8(ciphertext); Assert.Equal(message, decryptedtext); } { var encrypted = "12c732611c6917ab5c57a1926973bc44a1586e94a783f81d05ce72518d9b0a80e2e13c7f"; // encrypted broken down: // priv.pubkey // ivbuf 12c732611c6917ab5c57a1926973bc44 // encrypted a1586e94a783f81d05ce72518d9b0a80 // sig e2e13c7f var alice = new Ecies { PrivateKey = aliceKey, PublicKey = bobKey.CreatePublicKey(), NoKey = true, ShortTag = true }; var bob = new Ecies { PrivateKey = bobKey, PublicKey = aliceKey.CreatePublicKey(), NoKey = true, ShortTag = true }; var ciphertext = alice.Encrypt(message); Assert.Equal(encrypted, ciphertext.ToHex()); var decryptedtext = bob.DecryptToUtf8(ciphertext); Assert.Equal(message, decryptedtext); } }