/// <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) { byte[] buffer = new byte[count]; SodiumLibrary.randombytes_buf(buffer, count); return(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)); } byte[] buffer = new byte[MAC_BYTES + message.Length]; SodiumCore.Init(); int ret = SodiumLibrary.crypto_secretbox_easy(buffer, message, message.Length, nonce, key); if (ret != 0) { throw new CryptographicException("Failed to create 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(this string hex) { const string IGNORED_CHARS = ":- "; byte[] arr = new byte[hex.Length >> 1]; IntPtr bin = Marshal.AllocHGlobal(arr.Length); int binLength; //we call sodium_hex2bin with some chars to be ignored int 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) { byte[] tmp = new byte[binLength]; Array.Copy(arr, 0, tmp, 0, binLength); return(tmp); } return(arr); }
/// <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>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)); } //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 bool trim = true; for (int 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) { byte[] temp = new byte[cipherText.Length - MAC_BYTES]; Array.Copy(cipherText, MAC_BYTES, temp, 0, cipherText.Length - MAC_BYTES); cipherText = temp; } } byte[] buffer = new byte[cipherText.Length - MAC_BYTES]; SodiumCore.Init(); int ret = SodiumLibrary.crypto_secretbox_open_easy(buffer, cipherText, cipherText.Length, nonce, key); if (ret != 0) { throw new CryptographicException("Failed to open SecretBox"); } return(buffer); }
/// <summary>Takes a byte array and returns a hex-encoded string.</summary> /// <param name="data">Data to be encoded.</param> /// <returns>Hex-encoded string, lodercase.</returns> /// <exception cref="OverflowException"></exception> public static string BinaryToHex(this byte[] data) { byte[] hex = new byte[data.Length * 2 + 1]; IntPtr ret = SodiumLibrary.sodium_bin2hex(hex, hex.Length, data, data.Length); if (ret == IntPtr.Zero) { throw new OverflowException("Internal error, encoding failed."); } return(Marshal.PtrToStringAnsi(ret)); }
/// <summary> /// Returns the version of libsodium in use. /// </summary> /// <returns> /// The sodium version string. /// </returns> public static string SodiumVersionString() { IntPtr ptr = SodiumLibrary.sodium_version_string(); return(Marshal.PtrToStringAnsi(ptr)); }
/// <summary> /// Gets a random number. /// </summary> /// <param name="upperBound">Integer between 0 and 2147483647.</param> /// <returns>An unpredictable value between 0 and upperBound (excluded).</returns> public static int GetRandomNumber(int upperBound) { int randomNumber = SodiumLibrary.randombytes_uniform(upperBound); return(randomNumber); }