/// <summary>Verifies a message signed with the Sign method.</summary> /// <param name="signedMessage">The signed message.</param> /// <param name="key">The 32 byte public key.</param> /// <returns>Message.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] Verify(byte[] signedMessage, byte[] key) { //validate the length of the key if (key == null || key.Length != PUBLIC_KEY_BYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", PUBLIC_KEY_BYTES)); } var buffer = new byte[signedMessage.Length]; long bufferLength = 0; var ret = SodiumLibrary.crypto_sign_open(buffer, ref bufferLength, signedMessage, signedMessage.Length, key); if (ret != 0) { throw new CryptographicException("Failed to verify signature."); } var final = new byte[bufferLength]; RuntimeShim.Copy(buffer, 0, final, 0, bufferLength); return(final); }
/// <summary> /// Encrypts a message with an authentication tag and additional data using AES-GCM. /// </summary> /// <param name="message">The message to be encrypted.</param> /// <param name="nonce">The 12 byte nonce.</param> /// <param name="key">The 32 byte key.</param> /// <param name="additionalData">The additional data; may be null, otherwise between 0 and 16 bytes.</param> /// <returns>The encrypted message with additional data.</returns> /// <remarks>The nonce should never ever be reused with the same key.</remarks> /// <remarks>The recommended way to generate it is to use GenerateNonce() for the first message, and increment it for each subsequent message using the same key.</remarks> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="AdditionalDataOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] Encrypt(byte[] message, byte[] nonce, byte[] key, byte[] additionalData = null) { //additionalData can be null if (additionalData == null) { additionalData = new byte[0x00]; } //validate the length of the key if (key == null || key.Length != KEYBYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", KEYBYTES)); } //validate the length of the nonce if (nonce == null || nonce.Length != NPUBBYTES) { throw new NonceOutOfRangeException("nonce", (nonce == null) ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", NPUBBYTES)); } //validate the length of the additionalData if (additionalData.Length > ABYTES || additionalData.Length < 0) { throw new AdditionalDataOutOfRangeException( string.Format("additionalData must be between {0} and {1} bytes in length.", 0, ABYTES)); } var cipher = new byte[message.Length + ABYTES]; var bin = Marshal.AllocHGlobal(cipher.Length); long cipherLength; var ret = SodiumLibrary.crypto_aead_aes256gcm_encrypt(bin, out cipherLength, message, message.Length, additionalData, additionalData.Length, null, nonce, key); Marshal.Copy(bin, cipher, 0, (int)cipherLength); Marshal.FreeHGlobal(bin); if (ret != 0) { throw new CryptographicException("Error encrypting message."); } if (cipher.Length == cipherLength) { return(cipher); } //remove the trailing nulls from the array var tmp = new byte[cipherLength]; RuntimeShim.Copy(cipher, 0, tmp, 0, cipherLength); return(tmp); }
/// <summary>Signs a message with Ed25519.</summary> /// <param name="message">The message.</param> /// <param name="key">The 64 byte private key.</param> /// <returns>Signed message.</returns> /// <exception cref="KeyOutOfRangeException"></exception> public static byte[] Sign(byte[] message, byte[] key) { //validate the length of the key if (key == null || key.Length != SECRET_KEY_BYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", SECRET_KEY_BYTES)); } var buffer = new byte[message.Length + BYTES]; long bufferLength = 0; SodiumLibrary.crypto_sign(buffer, ref bufferLength, message, message.Length, key); var final = new byte[bufferLength]; RuntimeShim.Copy(buffer, 0, final, 0, bufferLength); return(final); }