示例#1
0
        /// <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);
        }
示例#2
0
        /// <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);
        }
示例#3
0
        /// <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);
        }
示例#4
0
        /// <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);
        }
示例#5
0
        /// <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));
        }
示例#6
0
        /// <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);
        }
示例#7
0
        /// <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));
        }
示例#8
0
        /// <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);
        }
示例#9
0
            protected override byte[] HashFinal()
            {
                var buffer = new byte[bytes];

                SodiumLibrary.hash_final(hashStatePtr, buffer, bytes);
                return(buffer);
            }
示例#10
0
            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);
            }
示例#11
0
        /// <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);
        }
示例#12
0
        /// <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));
        }
示例#13
0
        /// <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);
        }
示例#14
0
        /// <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);
        }
示例#15
0
        /// <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));
        }
示例#16
0
        /// <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);
        }
示例#18
0
        /// <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);
        }
示例#19
0
        /// <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));
        }
示例#20
0
        /// <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);
        }
示例#21
0
 /// <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;
     }
 }
示例#22
0
        /// <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);
        }
示例#23
0
        /// <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);
        }
示例#24
0
        /// <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);
        }
示例#25
0
 /// <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;
     }
 }
示例#26
0
        /// <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);
        }
示例#27
0
        /// <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();
        }
示例#28
0
        /// <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);
        }
示例#29
0
        /// <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));
        }
示例#30
0
        /// <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));
        }