예제 #1
0
        /// <summary>
        /// Perform AEAD Decryption process on a byte array using a 16-byte <paramref name="Nonce"/> and 32-byte <paramref name="Key"/> using Gimli (as proposed to NIST, v1).
        /// </summary>
        /// <remarks>
        /// Can optionally supply an <paramref name="AdditionalData"/> byte array that will be processed with the <paramref name="Ciphertext"/> array
        /// (must be same bytes as was used during <see cref="AEADEncrypt"/>, and should not be null if any AdditionalData was used during encrpytion).
        /// The Tag/MAC (of length <see cref="TAG_BYTES"/>) is expected to be at the end of the input (len Message = len Ciphertext - TAG_BYTES).
        /// </remarks>
        /// <param name="Nonce"></param>
        /// <param name="Key"></param>
        /// <param name="AdditionalData"></param>
        /// <param name="Ciphertext"></param>
        /// <returns>The original Message OR NULL if verification fails.</returns>
        public static byte[] AEADDecryptVerify(byte[] Nonce, byte[] Key, ReadOnlySpan <byte> AdditionalData, ReadOnlySpan <byte> Ciphertext)
        {
            if ((Nonce?.Length ?? 0) != 16)
            {
                throw new ArgumentOutOfRangeException("Nonce", "Nonce must be 16 bytes (and not null).");
            }
            if ((Key?.Length ?? 0) != 32)
            {
                throw new ArgumentOutOfRangeException("Key", "Nonce must be 32 bytes (and not null).");
            }
            if (Ciphertext.Length < 16)
            {
                throw new ArgumentOutOfRangeException("Ciphertext", "Not enough data. Tag might be missing (input len < 16).");
            }

            Gimli24.Statev1 state = new Gimli24.Statev1(Nonce, Key);

            int ad_ptr = 0;

            while (ad_ptr + Gimli24.Statev1.RATE_BYTES <= AdditionalData.Length)
            {
                state.AbsorbBlock(AdditionalData.Slice(ad_ptr, Gimli24.Statev1.RATE_BYTES));
                ad_ptr += Gimli24.Statev1.RATE_BYTES;
            }
            state.AbsorbLastBlock(AdditionalData.Slice(ad_ptr, AdditionalData.Length % Gimli24.Statev1.RATE_BYTES));

            byte[]      output    = new byte[Ciphertext.Length - TAG_BYTES];
            Span <byte> out_slice = new Span <byte>(output);
            int         d_ptr     = 0;

            while (d_ptr + Gimli24.Statev1.RATE_BYTES <= output.Length) // last 16 bytes are the tag
            {
                state.StripBlock(Ciphertext.Slice(d_ptr, Gimli24.Statev1.RATE_BYTES), ref out_slice, d_ptr);
                d_ptr += Gimli24.Statev1.RATE_BYTES;
            }
            state.StripLastBlock(Ciphertext.Slice(d_ptr, Ciphertext.Length % Gimli24.Statev1.RATE_BYTES), ref out_slice, d_ptr);

            byte[] tag    = state.Squeeze();
            Int32  verify = 0;

            for (byte v = 0; v < TAG_BYTES; v++)
            {
                verify |= tag[v] ^ Ciphertext[Ciphertext.Length - TAG_BYTES + v];
            }
            if (verify == 0)
            {
                return(output);
            }
            else
            {
                return(null);
            }
        }
예제 #2
0
        /// <summary>
        /// Perform AEAD Decryption process on a byte array using a 16-byte <paramref name="Nonce"/> and
        /// 32-byte <paramref name="Key"/> using Gimli (as proposed to NIST, v1), and the <paramref name="Tag"/> output from <see cref="Gimliv1.AEADEncrypt_Detached"/>.
        /// </summary>
        /// <remarks>
        /// Can optionally supply an <paramref name="AdditionalData"/> byte array that will be processed with the <paramref name="Ciphertext"/> array
        /// (must be same bytes as was used during <see cref="Gimliv1.AEADEncrypt_Detached"/>, and should not be null if any AdditionalData was used
        /// during encrpytion).
        /// </remarks>
        /// <param name="Nonce"></param>
        /// <param name="Key"></param>
        /// <param name="AdditionalData"></param>
        /// <param name="Tag">Tag/MAC of length <see cref="TAG_BYTES"/></param>
        /// <param name="Ciphertext"></param>
        /// <returns>The original Message OR NULL if verification fails.</returns>
        public static byte[] AEADDecryptVerify_Detached(byte[] Nonce, byte[] Key, ReadOnlySpan <byte> AdditionalData, byte[] Tag, ReadOnlySpan <byte> Ciphertext)
        {
            if ((Nonce?.Length ?? 0) != 16)
            {
                throw new ArgumentOutOfRangeException("Nonce", "Nonce must be 16 bytes (and not null).");
            }
            if ((Key?.Length ?? 0) != 32)
            {
                throw new ArgumentOutOfRangeException("Key", "Nonce must be 32 bytes (and not null).");
            }
            if ((Tag?.Length ?? 0) != TAG_BYTES)
            {
                throw new ArgumentOutOfRangeException("Tag", $"Tag must be {TAG_BYTES} bytes (and not null).");
            }

            Gimli24.Statev1 state = new Gimli24.Statev1(Nonce, Key);

            int ad_ptr = 0;

            while (ad_ptr + Gimli24.Statev1.RATE_BYTES <= AdditionalData.Length)
            {
                state.AbsorbBlock(AdditionalData.Slice(ad_ptr, Gimli24.Statev1.RATE_BYTES));
                ad_ptr += Gimli24.Statev1.RATE_BYTES;
            }
            state.AbsorbLastBlock(AdditionalData.Slice(ad_ptr, AdditionalData.Length % Gimli24.Statev1.RATE_BYTES));

            byte[]      output    = new byte[Ciphertext.Length]; // ciphertext is same length as message, tag is separate
            Span <byte> out_slice = new Span <byte>(output);
            int         d_ptr     = 0;

            while (d_ptr + Gimli24.Statev1.RATE_BYTES <= output.Length) // last 16 bytes are the tag
            {
                state.StripBlock(Ciphertext.Slice(d_ptr, Gimli24.Statev1.RATE_BYTES), ref out_slice, d_ptr);
                d_ptr += Gimli24.Statev1.RATE_BYTES;
            }
            state.StripLastBlock(Ciphertext.Slice(d_ptr, Ciphertext.Length % Gimli24.Statev1.RATE_BYTES), ref out_slice, d_ptr);

            byte[] local_tag = state.Squeeze();
            Int32  verify    = 0;

            for (byte v = 0; v < TAG_BYTES; v++)
            {
                verify |= local_tag[v] ^ Tag[v];
            }
            if (verify == 0)
            {
                return(output);
            }
            else
            {
                return(null);
            }
        }
예제 #3
0
        /// <summary>
        /// Compute a hash of a byte array using Gimli (as proposed to NIST, v1)
        /// </summary>
        /// <param name="data"></param>
        /// <returns><see cref="HASH_LEN"/> bytes of Hash result</returns>
        public static byte[] ComputeHash(ReadOnlySpan <byte> data)
        {
            Gimli24.Statev1 state = new Gimli24.Statev1(); // zero state
            int             d_ptr = 0;

            while (d_ptr + Gimli24.Statev1.RATE_BYTES <= data.Length)
            {
                state.AbsorbBlock(data.Slice(d_ptr, Gimli24.Statev1.RATE_BYTES));
                d_ptr += 16;
            }
            state.AbsorbLastBlock(data.Slice(d_ptr, data.Length % Gimli24.Statev1.RATE_BYTES));
            byte[] result = new byte[32];
            state.Squeeze(result, 0);
            state.Permute();
            state.Squeeze(result, 16);
            return(result);
        }
예제 #4
0
        // encryption

        /// <summary>
        /// Perform AEAD Encryption process on a byte array using a 16-byte <paramref name="Nonce"/> and 32-byte <paramref name="Key"/> using Gimli (as proposed to NIST, v1).
        /// </summary>
        /// <remarks>
        /// Can optionally supply an <paramref name="AdditionalData"/> byte array that will be processed with the <paramref name="Message"/> array.
        /// The Tag/MAC is appended to the output, length <seealso cref="TAG_BYTES"/> (len Ciphertext = len Message + TAG_BYTES).
        /// </remarks>
        /// <param name="Nonce"></param>
        /// <param name="Key"></param>
        /// <param name="AdditionalData"></param>
        /// <param name="Message"></param>
        /// <returns>The encrypted Message + <see cref="TAG_BYTES"/> bytes of Tag/MAC</returns>
        public static byte[] AEADEncrypt(byte[] Nonce, byte[] Key, ReadOnlySpan <byte> AdditionalData, ReadOnlySpan <byte> Message)
        {
            if ((Nonce?.Length ?? 0) != 16)
            {
                throw new ArgumentOutOfRangeException("Nonce", "Nonce must be 16 bytes (and not null).");
            }
            if ((Key?.Length ?? 0) != 32)
            {
                throw new ArgumentOutOfRangeException("Key", "Key must be 32 bytes (and not null).");
            }

            Gimli24.Statev1 state = new Gimli24.Statev1(Nonce, Key);

            int ad_ptr = 0;

            while (ad_ptr + Gimli24.Statev1.RATE_BYTES <= AdditionalData.Length)
            {
                state.AbsorbBlock(AdditionalData.Slice(ad_ptr, Gimli24.Statev1.RATE_BYTES));
                ad_ptr += Gimli24.Statev1.RATE_BYTES;
            }
            state.AbsorbLastBlock(AdditionalData.Slice(ad_ptr, AdditionalData.Length % Gimli24.Statev1.RATE_BYTES));

            byte[]      output    = new byte[Message.Length + Gimli24.Statev1.RATE_BYTES];
            Span <byte> out_slice = new Span <byte>(output);
            int         d_ptr     = 0;

            while (d_ptr + Gimli24.Statev1.RATE_BYTES <= Message.Length)
            {
                state.MergeBlock(Message.Slice(d_ptr, Gimli24.Statev1.RATE_BYTES), ref out_slice, d_ptr);
                d_ptr += Gimli24.Statev1.RATE_BYTES;
            }
            state.MergeLastBlock(Message.Slice(d_ptr, Message.Length % Gimli24.Statev1.RATE_BYTES), ref out_slice, d_ptr);

            state.Squeeze(output, output.Length - TAG_BYTES);

            return(output);
        }