/// <summary>Creates a Box</summary> /// <param name="message">The message.</param> /// <param name="nonce">The 24 byte nonce.</param> /// <param name="secretKey">The secret key to sign message with.</param> /// <param name="publicKey">The recipient's public key.</param> /// <returns>The encrypted message.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] Create(byte[] message, byte[] nonce, byte[] secretKey, byte[] publicKey) { //validate the length of the secret key if (secretKey == null || secretKey.Length != SecretKeyBytes) { throw new KeyOutOfRangeException("secretKey", secretKey == null ? 0 : secretKey.Length, string.Format("key must be {0} bytes in length.", SecretKeyBytes)); } //validate the length of the public key if (publicKey == null || publicKey.Length != PublicKeyBytes) { throw new KeyOutOfRangeException("publicKey", publicKey == null ? 0 : secretKey.Length, string.Format("key must be {0} bytes in length.", PublicKeyBytes)); } //validate the length of the nonce if (nonce == null || nonce.Length != NONCE_BYTES) { throw new NonceOutOfRangeException("nonce", nonce == null ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", NONCE_BYTES)); } var buffer = new byte[message.Length + MAC_BYTES]; var ret = SodiumLibrary.crypto_box_easy(buffer, message, message.Length, nonce, publicKey, secretKey); if (ret != 0) { throw new CryptographicException("Failed to create PublicKeyBox"); } return(buffer); }
/// <summary>Converts Base64 encoded string to byte array.</summary> /// <param name="base64">Base64 encoded string.</param> /// <param name="ignoredChars">Characters which will be ignored in decoding.</param> /// <param name="variant">Base64 encoding variant</param> /// <exception cref="Exception"></exception> /// <returns>A byte array of decoded Base64 string</returns> public static byte[] Base64ToBinary(string base64, string ignoredChars, Base64Variant variant = Base64Variant.Original) { if (base64 == null) { throw new ArgumentNullException(nameof(base64), "Data is null, encoding failed"); } if (base64 == string.Empty) { return(new byte[] { }); } var bin = Marshal.AllocHGlobal(base64.Length); var ret = SodiumLibrary.sodium_base642bin(bin, base64.Length, base64, base64.Length, ignoredChars, out var binLength, out var lastChar, (int)variant); if (ret != 0) { throw new Exception("Internal error, decoding failed."); } var decodedArr = new byte[binLength]; Marshal.Copy(bin, decodedArr, 0, binLength); Marshal.FreeHGlobal(bin); return(decodedArr); }
/// <summary>Opens a detached Secret Box</summary> /// <param name="cipherText">The cipherText.</param> /// <param name="mac">The 16 byte mac.</param> /// <param name="nonce">The 24 byte nonce.</param> /// <param name="key">The 32 byte nonce.</param> /// <returns>The decrypted text.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="MacOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] OpenDetached(byte[] cipherText, byte[] mac, byte[] nonce, byte[] key) { //validate the length of the key if (key == null || key.Length != KEY_BYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", KEY_BYTES)); } //validate the length of the nonce if (nonce == null || nonce.Length != NONCE_BYTES) { throw new NonceOutOfRangeException("nonce", (nonce == null) ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", NONCE_BYTES)); } //validate the length of the mac if (mac == null || mac.Length != MAC_BYTES) { throw new MacOutOfRangeException("mac", (mac == null) ? 0 : mac.Length, string.Format("mac must be {0} bytes in length.", MAC_BYTES)); } var buffer = new byte[cipherText.Length]; var ret = SodiumLibrary.crypto_secretbox_open_detached(buffer, cipherText, mac, cipherText.Length, nonce, key); if (ret != 0) { throw new CryptographicException("Failed to open detached SecretBox"); } return(buffer); }
/// <summary>Converts a hex-encoded string to a byte array.</summary> /// <param name="hex">Hex-encoded data.</param> /// <returns>A byte array of the decoded string.</returns> /// <exception cref="Exception"></exception> public static byte[] HexToBinary(string hex) { const string IGNORED_CHARS = ":- "; var arr = new byte[hex.Length >> 1]; var bin = Marshal.AllocHGlobal(arr.Length); int binLength; //we call sodium_hex2bin with some chars to be ignored var ret = SodiumLibrary.sodium_hex2bin(bin, arr.Length, hex, hex.Length, IGNORED_CHARS, out binLength, null); Marshal.Copy(bin, arr, 0, binLength); Marshal.FreeHGlobal(bin); if (ret != 0) { throw new Exception("Internal error, decoding failed."); } //remove the trailing nulls from the array, if there were some format characters in the hex string before if (arr.Length != binLength) { var tmp = new byte[binLength]; Array.Copy(arr, 0, tmp, 0, binLength); return(tmp); } return(arr); }
/// <summary>Returns the hash in a string format, which includes the generated salt.</summary> /// <param name="password">The password.</param> /// <param name="opsLimit">Represents a maximum amount of computations to perform.</param> /// <param name="memLimit">Is the maximum amount of RAM that the function will use, in bytes.</param> /// <returns>Returns an zero-terminated ASCII encoded string of the computed password and hash.</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="OutOfMemoryException"></exception> public static string ArgonHashString(string password, long opsLimit, int memLimit) { if (password == null) { throw new ArgumentNullException("password", "Password cannot be null"); } if (opsLimit < 3) { throw new ArgumentOutOfRangeException("opsLimit", "opsLimit the number of passes, has to be at least 3"); } if (memLimit <= 0) { throw new ArgumentOutOfRangeException("memLimit", "memLimit cannot be zero or negative"); } var buffer = new byte[ARGON_STRBYTES]; var pass = Encoding.UTF8.GetBytes(password); var ret = SodiumLibrary.crypto_pwhash_str(buffer, pass, pass.LongLength, opsLimit, memLimit); if (ret != 0) { throw new OutOfMemoryException( "Internal error, hash failed (usually because the operating system refused to allocate the amount of requested memory)."); } return(Encoding.UTF8.GetString(buffer)); }
/// <summary>Creates a Secret Box</summary> /// <param name="message">The message.</param> /// <param name="nonce">The 24 byte nonce.</param> /// <param name="key">The 32 byte key.</param> /// <returns>The encrypted message.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] Create(byte[] message, byte[] nonce, byte[] key) { //validate the length of the key if (key == null || key.Length != KEY_BYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", KEY_BYTES)); } //validate the length of the nonce if (nonce == null || nonce.Length != NONCE_BYTES) { throw new NonceOutOfRangeException("nonce", (nonce == null) ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", NONCE_BYTES)); } //pad the message, to start with ZERO_BYTES null bytes var paddedMessage = new byte[message.Length + ZERO_BYTES]; Array.Copy(message, 0, paddedMessage, ZERO_BYTES, message.Length); var buffer = new byte[paddedMessage.Length]; var ret = SodiumLibrary.crypto_secretbox(buffer, paddedMessage, paddedMessage.Length, nonce, key); if (ret != 0) { throw new CryptographicException("Failed to create SecretBox"); } return(buffer); }
/// <summary> /// Decrypts a cipher with an authentication tag and additional data. /// </summary> /// <param name="cipher">The cipher to be decrypted.</param> /// <param name="nonce">The 8 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 decrypted cipher.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="AdditionalDataOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public ArraySegment <byte> Decrypt(ArraySegment <byte> cipher, byte[] nonce, byte[] key, ArraySegment <byte> additionalData) { //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)); } //additionalData can be null GCHandle hAddData; IntPtr pAddData; int adataLength; if (additionalData.Array == null) { hAddData = GCHandle.Alloc(Array.Empty <byte>(), GCHandleType.Pinned); pAddData = hAddData.AddrOfPinnedObject(); adataLength = 0; } else { hAddData = GCHandle.Alloc(additionalData.Array, GCHandleType.Pinned); pAddData = hAddData.AddrOfPinnedObject() + additionalData.Offset; adataLength = additionalData.Count; } // //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 message = _bufferPool.Rent(cipher.Count - ABYTES); var hMsg = GCHandle.Alloc(message, GCHandleType.Pinned); var hCipher = GCHandle.Alloc(cipher.Array, GCHandleType.Pinned); var ret = SodiumLibrary.crypto_aead_xchacha20poly1305_ietf_decrypt(hMsg.AddrOfPinnedObject(), out long messageLength, null, hCipher.AddrOfPinnedObject() + cipher.Offset, cipher.Count, pAddData, adataLength, nonce, key); hMsg.Free(); hAddData.Free(); hCipher.Free(); if (ret != 0) { throw new CryptographicException("Error decrypting message."); } return(new ArraySegment <byte>(message, 0, (int)messageLength)); }
/// <summary>Opens a Secret Box</summary> /// <param name="cipherText">The cipherText.</param> /// <param name="nonce">The 24 byte nonce.</param> /// <param name="key">The 32 byte nonce.</param> /// <returns>The decrypted text.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] Open(byte[] cipherText, byte[] nonce, byte[] key) { //validate the length of the key if (key == null || key.Length != KEY_BYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", KEY_BYTES)); } //validate the length of the nonce if (nonce == null || nonce.Length != NONCE_BYTES) { throw new NonceOutOfRangeException("nonce", (nonce == null) ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", NONCE_BYTES)); } var buffer = new byte[cipherText.Length]; var ret = SodiumLibrary.crypto_secretbox_open(buffer, cipherText, cipherText.Length, nonce, key); if (ret != 0) { throw new CryptographicException("Failed to open SecretBox"); } var final = new byte[buffer.Length - ZERO_BYTES]; Array.Copy(buffer, ZERO_BYTES, final, 0, buffer.Length - ZERO_BYTES); return(final); }
protected override byte[] HashFinal() { var buffer = new byte[bytes]; SodiumLibrary.hash_final(hashStatePtr, buffer, bytes); return(buffer); }
protected override void HashCore(byte[] array, int ibStart, int cbSize) { var subArray = new byte[cbSize]; Array.Copy(array, ibStart, subArray, 0, cbSize); SodiumLibrary.hash_update(hashStatePtr, subArray, cbSize); }
/// <summary>Hashes a message, with an optional key, using the BLAKE2b primitive.</summary> /// <param name="message">The message to be hashed.</param> /// <param name="key">The key; may be null, otherwise between 16 and 64 bytes.</param> /// <param name="bytes">The size (in bytes) of the desired result.</param> /// <returns>Returns a byte array.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="BytesOutOfRangeException"></exception> public static byte[] Hash(byte[] message, byte[] key, int bytes) { //validate the length of the key int keyLength; if (key != null) { if (key.Length > KEY_BYTES_MAX || key.Length < KEY_BYTES_MIN) { throw new KeyOutOfRangeException(string.Format("key must be between {0} and {1} bytes in length.", KEY_BYTES_MIN, KEY_BYTES_MAX)); } keyLength = key.Length; } else { key = new byte[0]; keyLength = 0; } //validate output length if (bytes > BYTES_MAX || bytes < BYTES_MIN) { throw new BytesOutOfRangeException("bytes", bytes, string.Format("bytes must be between {0} and {1} bytes in length.", BYTES_MIN, BYTES_MAX)); } var buffer = new byte[bytes]; SodiumLibrary.crypto_generichash(buffer, buffer.Length, message, message.Length, key, keyLength); return(buffer); }
/// <summary>Creates detached a Secret Box</summary> /// <param name="message">The message.</param> /// <param name="nonce">The 24 byte nonce.</param> /// <param name="key">The 32 byte key.</param> /// <returns>A detached object with a cipher and a mac.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static DetachedBox CreateDetached(byte[] message, byte[] nonce, byte[] key) { //validate the length of the key if (key == null || key.Length != KEY_BYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", KEY_BYTES)); } //validate the length of the nonce if (nonce == null || nonce.Length != NONCE_BYTES) { throw new NonceOutOfRangeException("nonce", (nonce == null) ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", NONCE_BYTES)); } var cipher = new byte[message.Length]; var mac = new byte[MAC_BYTES]; var ret = SodiumLibrary.crypto_secretbox_detached(cipher, mac, message, message.Length, nonce, key); if (ret != 0) { throw new CryptographicException("Failed to create detached SecretBox"); } return(new DetachedBox(cipher, mac)); }
/// <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>Decryptes messages via ChaCha20</summary> /// <param name="cipherText">The chipher text to be opened.</param> /// <param name="nonce">The 8 byte nonce.</param> /// <param name="key">The 32 byte key.</param> /// <returns>The decrypted message.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] DecryptChaCha20(byte[] cipherText, byte[] nonce, byte[] key) { //validate the length of the key if (key == null || key.Length != CHACHA20_KEY_BYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", CHACHA20_KEY_BYTES)); } //validate the length of the nonce if (nonce == null || nonce.Length != CHACHA20_NONCEBYTES) { throw new NonceOutOfRangeException("nonce", (nonce == null) ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", CHACHA20_NONCEBYTES)); } var buffer = new byte[cipherText.Length]; var ret = SodiumLibrary.crypto_stream_chacha20_xor(buffer, cipherText, cipherText.Length, nonce, key); if (ret != 0) { throw new CryptographicException("Error derypting message."); } return(buffer); }
/// <summary>Creates a detached Box</summary> /// <param name="message">The message.</param> /// <param name="nonce">The 24 byte nonce.</param> /// <param name="secretKey">The secret key to sign message with.</param> /// <param name="publicKey">The recipient's public key.</param> /// <returns>A detached object with a cipher and a mac.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static DetachedBox CreateDetached(byte[] message, byte[] nonce, byte[] secretKey, byte[] publicKey) { //validate the length of the secret key if (secretKey == null || secretKey.Length != SecretKeyBytes) { throw new KeyOutOfRangeException("secretKey", (secretKey == null) ? 0 : secretKey.Length, string.Format("key must be {0} bytes in length.", SecretKeyBytes)); } //validate the length of the public key if (publicKey == null || publicKey.Length != PublicKeyBytes) { throw new KeyOutOfRangeException("publicKey", (publicKey == null) ? 0 : secretKey.Length, string.Format("key must be {0} bytes in length.", PublicKeyBytes)); } //validate the length of the nonce if (nonce == null || nonce.Length != NONCE_BYTES) { throw new NonceOutOfRangeException("nonce", (nonce == null) ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", NONCE_BYTES)); } var cipher = new byte[message.Length]; var mac = new byte[MAC_BYTES]; var ret = SodiumLibrary.crypto_box_detached(cipher, mac, message, message.Length, nonce, secretKey, publicKey); if (ret != 0) { throw new CryptographicException("Failed to create public detached Box"); } return(new DetachedBox(cipher, mac)); }
/// <summary>Returns the hash in a string format, which includes the generated salt.</summary> /// <param name="password">The password.</param> /// <param name="opsLimit">Represents a maximum amount of computations to perform.</param> /// <param name="memLimit">Is the maximum amount of RAM that the function will use, in bytes.</param> /// <returns>Returns an zero-terminated ASCII encoded string of the computed password and hash.</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="OutOfMemoryException"></exception> public static string ScryptHashString(string password, long opsLimit, int memLimit) { if (password == null) { throw new ArgumentNullException("password", "Password cannot be null"); } if (opsLimit <= 0) { throw new ArgumentOutOfRangeException("opsLimit", "opsLimit cannot be zero or negative"); } if (memLimit <= 0) { throw new ArgumentOutOfRangeException("memLimit", "memLimit cannot be zero or negative"); } var buffer = new byte[SCRYPT_SALSA208_SHA256_STRBYTES]; var pass = Encoding.UTF8.GetBytes(password); SodiumCore.Init(); var ret = SodiumLibrary.crypto_pwhash_scryptsalsa208sha256_str(buffer, pass, pass.Length, opsLimit, memLimit); if (ret != 0) { throw new OutOfMemoryException("Internal error, hash failed (usually because the operating system refused to allocate the amount of requested memory)."); } return(Encoding.UTF8.GetString(buffer)); }
/// <summary>Opens a SealedPublicKeyBox</summary> /// <param name="cipherText">The cipherText to be opened.</param> /// <param name="recipientSecretKey">The recipient's secret key.</param> /// <param name="recipientPublicKey">The recipient's public key.</param> /// <returns>The decrypted message.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] Open(byte[] cipherText, byte[] recipientSecretKey, byte[] recipientPublicKey) { //validate the length of the recipient secret key if (recipientSecretKey == null || recipientSecretKey.Length != RecipientSecretKeyBytes) { throw new KeyOutOfRangeException("recipientPublicKey", (recipientSecretKey == null) ? 0 : recipientSecretKey.Length, string.Format("recipientSecretKey must be {0} bytes in length.", RecipientSecretKeyBytes)); } //validate the length of the recipient public key if (recipientPublicKey == null || recipientPublicKey.Length != RecipientPublicKeyBytes) { throw new KeyOutOfRangeException("recipientPublicKey", (recipientPublicKey == null) ? 0 : recipientPublicKey.Length, string.Format("recipientPublicKey must be {0} bytes in length.", RecipientPublicKeyBytes)); } var buffer = new byte[cipherText.Length - CryptoBoxSealbytes]; var ret = SodiumLibrary.crypto_box_seal_open(buffer, cipherText, cipherText.Length, recipientPublicKey, recipientSecretKey); if (ret != 0) { throw new CryptographicException("Failed to open SealedBox"); } return(buffer); }
/// <summary>Encryptes messages via XSalsa20</summary> /// <param name="message">The message to be encrypted.</param> /// <param name="nonce">The nonce.</param> /// <param name="key">The key.</param> /// <returns>The encrypted message.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] Encrypt(byte[] message, byte[] nonce, byte[] key) { //validate the length of the key if (key == null || key.Length != XSALSA20_KEY_BYTES) { throw new KeyOutOfRangeException("key", (key == null) ? 0 : key.Length, string.Format("key must be {0} bytes in length.", XSALSA20_KEY_BYTES)); } //validate the length of the nonce if (nonce == null || nonce.Length != XSALSA20_NONCE_BYTES) { throw new NonceOutOfRangeException("nonce", (nonce == null) ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", XSALSA20_NONCE_BYTES)); } var buffer = new byte[message.Length]; var ret = SodiumLibrary.crypto_stream_xor(buffer, message, message.Length, nonce, key); if (ret != 0) { throw new CryptographicException("Error encrypting message."); } return(buffer); }
/// <summary>Returns the hash in a string format, which includes the generated salt.</summary> /// <param name="password">The password.</param> /// <param name="opsLimit">Represents a maximum amount of computations to perform.</param> /// <param name="memLimit">Is the maximum amount of RAM that the function will use, in bytes.</param> /// <returns>Returns an zero-terminated ASCII encoded string of the computed password and hash.</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="OutOfMemoryException"></exception> public static string ScryptHashString(string password, long opsLimit, int memLimit) { if (password == null) { throw new ArgumentNullException("password", "Password cannot be null"); } if (opsLimit <= 0) { throw new ArgumentOutOfRangeException("opsLimit", "opsLimit cannot be zero or negative"); } if (memLimit <= 0) { throw new ArgumentOutOfRangeException("memLimit", "memLimit cannot be zero or negative"); } var buffer = new byte[SCRYPT_SALSA208_SHA256_BYTES]; var pass = Encoding.UTF8.GetBytes(password); var ret = SodiumLibrary.crypto_pwhash_scryptsalsa208sha256_str(buffer, pass, pass.LongLength, opsLimit, memLimit); if (ret != 0) { throw new OutOfMemoryException("Internal error, hash failed"); } return(Encoding.UTF8.GetString(buffer)); }
/// <summary>Opens a Box</summary> /// <param name="cipherText"></param> /// <param name="nonce">The 24 byte nonce.</param> /// <param name="secretKey">The recipient's secret key.</param> /// <param name="publicKey">The sender's public key.</param> /// <returns>The decrypted message.</returns> /// <exception cref="KeyOutOfRangeException"></exception> /// <exception cref="NonceOutOfRangeException"></exception> /// <exception cref="CryptographicException"></exception> public static byte[] Open(byte[] cipherText, byte[] nonce, byte[] secretKey, byte[] publicKey) { //validate the length of the secret key if (secretKey == null || secretKey.Length != SecretKeyBytes) { throw new KeyOutOfRangeException("secretKey", secretKey == null ? 0 : secretKey.Length, string.Format("key must be {0} bytes in length.", SecretKeyBytes)); } //validate the length of the public key if (publicKey == null || publicKey.Length != PublicKeyBytes) { throw new KeyOutOfRangeException("publicKey", publicKey == null ? 0 : secretKey.Length, string.Format("key must be {0} bytes in length.", PublicKeyBytes)); } //validate the length of the nonce if (nonce == null || nonce.Length != NONCE_BYTES) { throw new NonceOutOfRangeException("nonce", nonce == null ? 0 : nonce.Length, string.Format("nonce must be {0} bytes in length.", NONCE_BYTES)); } //check to see if there are MAC_BYTES of leading nulls, if so, trim. //this is required due to an error in older versions. if (cipherText[0] == 0) { //check to see if trim is needed var trim = true; for (var i = 0; i < MAC_BYTES - 1; i++) { if (cipherText[i] != 0) { trim = false; break; } } //if the leading MAC_BYTES are null, trim it off before going on. if (trim) { var temp = new byte[cipherText.Length - MAC_BYTES]; Array.Copy(cipherText, MAC_BYTES, temp, 0, cipherText.Length - MAC_BYTES); cipherText = temp; } } var buffer = new byte[cipherText.Length - MAC_BYTES]; var ret = SodiumLibrary.crypto_box_open_easy(buffer, cipherText, cipherText.Length, nonce, publicKey, secretKey); if (ret != 0) { throw new CryptographicException("Failed to open PublicKeyBox"); } return(buffer); }
/// <summary>Initialize libsodium.</summary> /// <remarks>This only needs to be done once, so this prevents repeated calls.</remarks> internal static void Init() { if (!_isInit) { SodiumLibrary.init(); _isInit = true; } }
/// <summary>Hashes a byte array using the SHA256 algorithm</summary> /// <param name="message">The message.</param> /// <returns></returns> public static byte[] Sha256(byte[] message) { var buffer = new byte[SHA256_BYTES]; SodiumLibrary.crypto_hash_sha256(buffer, message, message.Length); return(buffer); }
/// <summary>Hashes a byte array using the default algorithm (This is what you want to use)</summary> /// <param name="message">The message.</param> /// <returns></returns> public static byte[] Hash(byte[] message) { var buffer = new byte[SHA512_BYTES]; SodiumLibrary.crypto_hash(buffer, message, message.Length); return(buffer); }
/// <summary> /// Takes a unsigned number, and increments it. /// </summary> /// <param name="value">The value to increment.</param> /// <returns>The incremented value.</returns> public static byte[] Increment(byte[] value) { var buffer = value; SodiumLibrary.sodium_increment(buffer, buffer.Length); return(buffer); }
/// <summary>Initialize libsodium.</summary> /// <remarks>This only needs to be done once, so this prevents repeated calls.</remarks> public static void Init() { if (!_isInit) { SodiumLibrary.sodium_init(); _isInit = true; } }
/// <summary>Gets random bytes</summary> /// <param name="count">The count of bytes to return.</param> /// <returns>An array of random bytes.</returns> public static byte[] GetRandomBytes(int count) { var buffer = new byte[count]; SodiumLibrary.randombytes_buf(buffer, count); return(buffer); }
/// <summary>Initialize libsodium.</summary> /// <remarks>This only needs to be done once, so this prevents repeated calls.</remarks> public static void Init(bool pinDll = true) { if (pinDll) { RuntimeShim.PinDllImportLibrary(SodiumLibrary.Name); } SodiumLibrary.sodium_init(); }
/// <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]; Array.Copy(cipher, 0, tmp, 0, cipherLength); return(tmp); }
/// <summary>Creates a new key pair based on a random seed.</summary> /// <returns>A KeyPair.</returns> public static KeyPair GenerateKeyPair() { var publicKey = new byte[PublicKeyBytes]; var privateKey = new byte[SecretKeyBytes]; SodiumLibrary.crypto_box_keypair(publicKey, privateKey); return(new KeyPair(publicKey, privateKey)); }
/// <summary>Creates a new key pair based on a random seed.</summary> /// <returns>A KeyPair.</returns> public static KeyPair GenerateKeyPair() { var publicKey = new byte[PUBLIC_KEY_BYTES]; var privateKey = new byte[SECRET_KEY_BYTES]; SodiumLibrary.crypto_sign_keypair(publicKey, privateKey); return(new KeyPair(publicKey, privateKey)); }