/// <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);
        }
Beispiel #2
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];

            RuntimeShim.Copy(cipher, 0, tmp, 0, cipherLength);

            return(tmp);
        }
Beispiel #3
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();
        }
Beispiel #4
0
        /// <summary>Initializes a new instance of the <see cref="KeyPair"/> class.</summary>
        /// <param name="publicKey">The public key.</param>
        /// <param name="privateKey">The private key.</param>
        /// <exception cref="KeyOutOfRangeException"></exception>
        public KeyPair(byte[] publicKey, byte[] privateKey)
        {
            //verify that the private key length is a multiple of 16
            if (privateKey.Length % 16 != 0)
            {
                throw new KeyOutOfRangeException("Private Key length must be a multiple of 16 bytes.");
            }

            _publicKey = publicKey;

            _privateKey = privateKey;
            RuntimeShim.ProtectMemory(_privateKey);
        }
        /// <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);
        }