找传奇、传世资源到传世资源站!

TweetNaCl

8.5玩家评分(1人评分)
下载后可评
介绍 评论 失效链接反馈

TweetNaCl开源代码,编译成dll生成sealed加密。
/*
 *This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace NaCl
{
    public class TweetNaCl
    {
        #region Public-key cryptography - Implementation of curve25519-xsalsa20-poly1305

        /// <summary>
        /// crypto_scalarmult_curve25519
        /// </summary>
        public static readonly Int32 ScalarmultBytes = 32;

        /// <summary>
        /// crypto_scalarmult_curve25519
        /// </summary>
        public static readonly Int32 ScalarBytes = 32;
        
        /// <summary>
        /// crypto_box_beforenm computed shared key size 
        /// </summary>
        public static readonly Int32 BoxBeforenmBytes = 32;
        public static readonly Int32 BoxPublicKeyBytes = 32;
        public static readonly Int32 BoxSecretKeyBytes = 32;
        public static readonly Int32 BoxNonceBytes = 24;
        public static readonly Int32 BoxZeroBytes = 32;
        public static readonly Int32 BoxBoxZeroBytes = 16;

        public static readonly Int32 SecretBoxNonceBytes = 24;
        public static readonly Int32 SecretBoxKeyBytes = 32;
        
        /// <summary>
        /// SHA-512 hash bytes
        /// </summary>
        public static readonly Int32 HashBytes = 64;
        
        public static readonly Int32 SignPublicKeyBytes = 32;
        public static readonly Int32 SignSecretKeyBytes = 64;

        public static readonly Int32 SignBytes = 64;

        public class InvalidSignatureException : CryptographicException { }
        public class InvalidCipherTextException : CryptographicException { }
        public class InvalidEncryptionKeypair : CryptographicException { }

        /// <summary>
        /// Scalar multiplication is a curve25519 implementation.
        /// </summary>
        /// <param name="n"></param>
        /// <param name="p"></param>
        /// <returns>the resulting group element q of length SCALARMULT_BYTES.</returns>
        public static Byte[] CryptoScalarmult(Byte[] n, Byte[] p)
        {
            Byte[] q = new Byte[ScalarmultBytes];
            Byte[] z = new Byte[32];
            Int64[] x = new Int64[80];
            Int64[] a = new Int64[GF_LEN],
                b = new Int64[GF_LEN],
                c = new Int64[GF_LEN],
                d = new Int64[GF_LEN],
                e = new Int64[GF_LEN],
                f = new Int64[GF_LEN]
            ;

            Int32 r = 0;

            for (var i = 0; i < 31; i)
            {
                z[i] = n[i];
            }

            z[31] = (Byte)((n[31] & 127) | 64);
            z[0] &= 248;

            Unpack25519(x, p);

            for (var i = 0; i < 16; i)
            {
                b[i] = x[i];
                d[i] = a[i] = c[i] = 0;
            }

            a[0] = d[0] = 1;

            for (var i = 254; i >= 0; --i)
            {
                r = ((0xff & z[i >> 3]) >> (i & 7)) & 1;
                Sel25519(a, b, r);
                Sel25519(c, d, r);
                A(e, a, c);
                Z(a, a, c);
                A(c, b, d);
                Z(b, b, d);
                S(d, e);
                S(f, a);
                M(a, 0, c, 0, a, 0);
                M(c, 0, b, 0, e, 0);
                A(e, a, c);
                Z(a, a, c);
                S(b, a);
                Z(c, d, f);
                M(a, 0, c, 0, _121665, 0);
                A(a, a, d);
                M(c, 0, c, 0, a, 0);
                M(a, 0, d, 0, f, 0);
                M(d, 0, b, 0, x, 0);
                S(b, e);
                Sel25519(a, b, r);
                Sel25519(c, d, r);
            }
            for (var i = 0; i < 16; i)
            {
                x[i 16] = a[i];
                x[i 32] = c[i];
                x[i 48] = b[i];
                x[i 64] = d[i];
            }

            Inv25519(x, 32, x, 32);

            M(x, 16, x, 16, x, 32);

            Pack25519(q, x, 16);

            return q;
        }

        /// <summary>
        /// The crypto_box_keypair function randomly generates a secret key and a corresponding public key. 
        /// It guarantees that sk has crypto_box_SECRETKEYBYTES bytes and that pk has crypto_box_PUBLICKEYBYTES bytes. 
        /// </summary>
        /// <returns>Generated KeyPair</returns>
        public static KeyPair CryptoBoxKeypair()
        {
            Byte[] secretKey = new Byte[BoxSecretKeyBytes];
            RandomBytes(secretKey);
            Byte[] publicKey = CryptoScalarmultBase(secretKey);

            return new KeyPair(publicKey, secretKey);
        }

        /// <summary>
        /// The crypto_box_keypair function randomly generates a secret key and a corresponding public key. 
        /// It guarantees that sk has crypto_box_SECRETKEYBYTES bytes and that pk has crypto_box_PUBLICKEYBYTES bytes. 
        /// </summary>
        /// <param name="secretKey">generated secret key</param>
        /// <returns>generated public key</returns>
        public static Byte[] CryptoBoxKeypair(Byte[] secretKey)
        {
            RandomBytes(secretKey);
            return CryptoScalarmultBase(secretKey);
        }

        /// <summary>
        /// The intermediate data computed by crypto_box_beforenm
        /// Applications that send several messages to the same receiver can gain speed by splitting CryptoBox into two steps, 
        /// <b>CryptoBoxBeforenm</b> and CryptoBoxAfternm. 
        /// </summary>
        /// <param name="publicKey"></param>
        /// <param name="secretKey"></param>
        /// <returns>
        ///     shared key to be used with afternm
        /// </returns>
        public static Byte[] CryptoBoxBeforenm(Byte[] publicKey, Byte[] secretKey)
        {
            Byte[] s = CryptoScalarmult(secretKey, publicKey);
            return CryptoCoreHSalsa20(_0, s, Sigma);
        }

        /// <summary>
        /// Applications that send several messages to the same receiver can gain speed by splitting CryptoBox into two steps, 
        /// CryptoBoxBeforenm and <b>CryptoBoxAfternm</b>. 
        /// </summary>
        /// <param name="cipheredMessage"></param>
        /// <param name="paddedMessage"></param>
        /// <param name="nonce"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static Byte[] CryptoBoxAfternm(Byte[] message, Byte[] nonce, Byte[] k)
        {
            return CryptoSecretBox(message, nonce, k);
        }

        /// <summary>
        /// Applications that receive several messages from the same 
        /// sender can gain speed by splitting CryptoBoxOpen into two steps, CryptoBoxBeforenm and <b>CryptoBoxOpenAfternm</b>. 
        /// </summary>
        /// <param name="paddedMessage"></param>
        /// <param name="cipheredMessage"></param>
        /// <param name="nonce"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static Byte[] CryptoBoxOpenAfternm(Byte[] cipheredMessage, Byte[] nonce, Byte[] k)
        {
            return CryptoSecretBoxOpen(cipheredMessage, nonce, k);
        }

        /// <summary>
        /// The crypto_box function encrypts and authenticates a message m, remember that all 
        /// messages are 0-padded versions of messages with BOX_ZEROBYTES.
        /// </summary>
        /// <param name="cipheredMessage"></param>
        /// <param name="paddedMessage"></param>
        /// <param name="nonce"></param>
        /// <param name="publicKey"></param>
        /// <param name="secretKey"></param>
        /// <returns>
        ///     0 for success or -1 for failure
        /// </returns>
        public static Byte[] CryptoBox(Byte[] message, Byte[] nonce, Byte[] publicKey, Byte[] secretKey)
        {
            Byte[] k = CryptoBoxBeforenm(publicKey, secretKey);
            return CryptoBoxAfternm(message, nonce, k);
        }

        /// <summary>
        /// The crypto_box_open function verifies and decrypts a ciphertext
        /// </summary>
        /// <param name="paddedMessage"></param>
        /// <param name="cipheredMessage"></param>
        /// <param name="d"></param>
        /// <param name="nonce"></param>
        /// <param name="publicKey"></param>
        /// <param name="secretKey"></param>
        /// <returns>
        ///     0 for success or -1 for failure
        /// </returns>
        public static Byte[] CryptoBoxOpen(Byte[] cipheredMessage, Byte[] nonce, Byte[] publicKey, Byte[] secretKey)
        {
            Byte[] k = CryptoBoxBeforenm(publicKey, secretKey);
            return CryptoBoxOpenAfternm(cipheredMessage, nonce, k);
        }

        /// <summary>
        /// Randomly generates a secret key and a corresponding public key NaCl-compatible Ed25519 https://ed25519.cr.yp.to/
        /// </summary>
        /// <param name="publicKey"></param>
        /// <param name="secretKey"></param>
        /// <returns></returns>
        public static Byte[] CryptoSignKeypair(Byte[] secretKey)
        {
            Byte[] publicKey = new Byte[SignPublicKeyBytes];
            Byte[] d = new Byte[64];
            Int64[][] /*gf*/ p = new Int64[4][] { new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN] };

            RandomBytes(secretKey);

            if (CryptoHash(d, secretKey, 32) != 0)
            {
                throw new InvalidSignatureException();
            }

            d[0] &= 248;
            d[31] &= 127;
            d[31] |= 64;

            Scalarbase(p, d, 0);
            Pack(publicKey, p);

            for (var i = 0; i < 32; i)
            {
                secretKey[32 i] = publicKey[i];
            }

            return publicKey;
        }
        
        /// <summary>
        /// The crypto_sign function signs a message m using the signer's secret key secretKey.
        /// </summary>
        /// <param name="signedMessage"></param>
        /// <param name="message"></param>
        /// <param name="n"></param>
        /// <param name="secretKey"></param>
        /// <returns></returns>
        public static Byte[] CryptoSign(Byte[] message, Byte[] secretKey)
        {
            Byte[] signedMessage = new Byte[SignBytes message.Length];

            Byte[] d = new Byte[64];
            Byte[] h = new Byte[64];
            Byte[] r = new Byte[64];
            Int64[] x = new Int64[64];
            Int64[][] /*gf*/ p/*[4]*/ = new Int64[4][] { new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN] };

            CryptoHash(d, secretKey, 32);

            d[0] &= 248;
            d[31] &= 127;
            d[31] |= 64;

            for (var i = 0; i < message.Length; i)
            {
                signedMessage[64 i] = message[i];
            }

            for (var i = 0; i < 32; i)
            {
                signedMessage[32 i] = d[32 i];
            }

            Byte[] smd = new Byte[signedMessage.Length];
            Array.Copy(signedMessage, 32, smd, 0, signedMessage.Length - 32);
            CryptoHash(r, smd, message.Length 64);

            Reduce(r);
            Scalarbase(p, r, 0);
            Pack(signedMessage, p);

            for (int i = 0; i < 32; i)
            {
                signedMessage[i 32] = secretKey[i 32];
            }

            CryptoHash(h, signedMessage, message.Length 64);
            Reduce(h);

            for (var i = 0; i < 64; i)
            {
                x[i] = 0;
            }

            for (var i = 0; i < 32; i)
            {
                x[i] = 0xff & r[i];
            }

            for (var i = 0; i < 32; i)
            {
                for (int j = 0; j < 32; j)
                {
                    x[i j] = (0xff & h[i]) * (0xff & d[j]);
                }
            }

            ModL(signedMessage, 32, x);

            return signedMessage;
        }

        /// <summary>
        /// The CryptoSignOpen function verifies the signature
        /// </summary>
        /// <param name="message">returned clear message</param>
        /// <param name="signedMessage">signed message</param>
        /// <param name="publicKey">public key</param>
        /// <returns></returns>
        public static Byte[] CryptoSignOpen(Byte[] signedMessage, Byte[] publicKey)
        {
            Byte[] message = new Byte[signedMessage.Length - 64];

            Byte[] t = new Byte[32];
            Byte[] h = new Byte[64];
            Int64[][] /*gf*/ p = new Int64[4][] { new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN] };
            Int64[][] /*gf*/ q = new Int64[4][] { new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN] };
            Int32 messageSize = signedMessage.Length;

            Byte[] tsm = new Byte[signedMessage.Length];

            if (signedMessage.Length < 64)
            {
                throw new InvalidSignatureException();
            }

            if (Unpackneg(q, publicKey) != 0)
            {
                throw new InvalidSignatureException();
            }

            for (var i = 0; i < signedMessage.Length; i)
            {
                tsm[i] = signedMessage[i];
            }

            for (var i = 0; i < 32; i)
            {
                tsm[i 32] = publicKey[i];
            }

            CryptoHash(h, tsm, signedMessage.Length);
            Reduce(h);
            Scalarmult(p, q, h, 0);

            Scalarbase(q, signedMessage, 32);
            Add(p, q);
            Pack(t, p);

            if (CryptoVerify32(signedMessage, t) != 0)
            {
                for (var i = 0; i < messageSize; i)
                {
                    tsm[i] = 0;
                }

                throw new InvalidSignatureException();
            }

            for (var i = 0; i < signedMessage.Length - 64; i)
            {
                message[i] = signedMessage[i 64];
            }

            return message;
        }

        #endregion

        #region private methods

        #region Curve25519

        private static Byte[] Core(Byte[] pout, Byte[] pin, Byte[] k, Byte[] c, Boolean hsalsa)
        {
            UInt32[] w = new UInt32[16];
            UInt32[] x = new UInt32[16];
            UInt32[] y = new UInt32[16];
            UInt32[] t = new UInt32[4];

            Int32 i, j, m;

            for (i = 0; i < 4; i )
            {
                x[5 * i] = Ld32(c, 4 * i);
                x[1 i] = Ld32(k, 4 * i);
                x[6 i] = Ld32(pin, 4 * i);
                x[11 i] = Ld32(k, 16 4 * i);
            }

            for (i = 0; i < 16; i)
            {
                y[i] = x[i];
            }

            for (i = 0; i < 20; i)
            {
                for (j = 0; j < 4; j)
                {
                    for (m = 0; m < 4; m)
                    {
                        t[m] = x[(5 * j 4 * m) % 16];
                    }

                    t[1] ^= L32(t[0] t[3], 7);
                    t[2] ^= L32(t[1] t[0], 9);
                    t[3] ^= L32(t[2] t[1], 13);
                    t[0] ^= L32(t[3] t[2], 18);

                    for (m = 0; m < 4; m)
                    {
                        w[4 * j (j m) % 4] = t[m];
                    }
                }

                for (m = 0; m < 16; m)
                {
                    x[m] = w[m];
                }
            }

            if (hsalsa)
            {
                for (i = 0; i < 16; i)
                {
                    x[i] = y[i];
                }

                for (i = 0; i < 4; i)
                {
                    x[5 * i] -= Ld32(c, 4 * i);
                    x[6 i] -= Ld32(pin, 4 * i);
                }

                for (i = 0; i < 4; i)
                {
                    St32(pout, x[5 * i], 4 * i);
                    St32(pout, x[6 i], 16 4 * i);
                }
            }
            else
            {
                for (i = 0; i < 16; i)
                {
                    St32(pout, x[i] y[i], 4 * i);
                }
            }

            return pout;
        }

        private static Byte[] CryptoCoreHSalsa20(Byte[] pin, Byte[] k, Byte[] c)
        {
            Byte[] pout = new Byte[BoxBeforenmBytes];
            return Core(pout, pin, k, c, true);
        }
        
        /// <summary>
        /// The crypto_scalarmult_base function computes the scalar product of a standard group element and an integer n.
        /// </summary>
        /// <param name="n"></param>
        /// <returns>It returns the resulting group element q of length SCALARMULT_BYTES</returns>
        private static Byte[] CryptoScalarmultBase(Byte[] n)
        {
            return CryptoScalarmult(n, _9);
        }
        
        private static void Set25519(Int64[] /*gf*/ r, Int64[] /*gf*/ a)
        {
            for (var i = 0; i < 16; i)
            {
                r[i] = a[i];
            }
        }

        private static void Car25519(Int64[] /*gf*/ o, Int32 oOffset)
        {
            for (var i = 0; i < 16; i)
            {
                o[oOffset i] = (1 << 16);
                Int64 c = o[oOffset i] >> 16;
                o[oOffset (i 1) * (i < 15 ? 1 : 0)] = c - 1 37 * (c - 1) * (i == 15 ? 1 : 0);
                o[oOffset i] -= c << 16;
            }
        }

        private static void Sel25519(Int64[] /*gf*/ p, Int64[] /*gf*/ q, Int32 b)
        {
            Int64 t, c = ~(b - 1);
            for (var i = 0; i < 16; i)
            {
                t = c & (p[i] ^ q[i]);
                p[i] ^= t;
                q[i] ^= t;
            }
        }

        private static void Pack25519(Byte[] o, Int64[] /*gf*/ n, Int32 nOffset)
        {
            Int32 b = 0, i, j;
            Int64[] /*gf*/ m = new Int64[GF_LEN], t = new Int64[GF_LEN];

            for (i = 0; i < 16; i)
            {
                t[i] = n[nOffset i];
            }

            Car25519(t, 0);
            Car25519(t, 0);
            Car25519(t, 0);

            for (j = 0; j < 2; j)
            {
                m[0] = t[0] - 0xffed;

                for (i = 1; i < 15; i )
                {
                    m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
                    m[i - 1] &= 0xffff;
                }

                m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
                b = (Int32)((m[15] >> 16) & 1);
                m[14] &= 0xffff;
                Sel25519(t, m, 1 - b);
            }

            for (i = 0; i < 16; i)
            {
                o[2 * i] = (Byte)t[i];
                o[2 * i 1] = (Byte)(t[i] >> 8);
            }
        }

        private static Int32 Neq25519(Int64[] /*gf*/ a, Int64[] /*gf*/ b)
        {
            Byte[] c = new Byte[32], d = new Byte[32];
            Pack25519(c, a, 0);
            Pack25519(d, b, 0);
            return CryptoVerify32(c, d);
        }

        private static Byte Par25519(Int64[] /*gf*/ a)
        {
            Byte[] d = new Byte[32];

            Pack25519(d, a, 0);

            return (Byte)(d[0] & 1);
        }

        private static void Unpack25519(Int64[] /*gf*/ o, Byte[] n)
        {
            for (var i = 0; i < 16; i)
            {
                o[i] = (0xff & n[2 * i]) ((0xffL & n[2 * i 1]) << 8);
            }

            o[15] &= 0x7fff;
        }

        private static void A(Int64[] /*gf*/ o, Int64[] /*gf*/ a, Int64[] /*gf*/ b)
        {
            for (var i = 0; i < 16; i)
            {
                o[i] = a[i] b[i];
            }
        }

        private static void Z(Int64[] /*gf*/ o, Int64[] /*gf*/ a, Int64[] /*gf*/ b)
        {
            for (var i = 0; i < 16; i)
            {
                o[i] = a[i] - b[i];
            }
        }

        private static void M(Int64[] /*gf*/ o, Int32 oOffset, Int64[] /*gf*/ a, Int32 aOffset, Int64[] /*gf*/ b, Int32 bOffset)
        {
            Int64[] t = new Int64[31];

            for (var i = 0; i < 31; i)
            {
                t[i] = 0;
            }

            for (var i = 0; i < 16; i)
            {
                for (var j = 0; j < 16; j)
                {
                    t[i j] = a[aOffset i] * b[bOffset j];
                }
            }

            for (var i = 0; i < 15; i)
            {
                t[i] = 38 * t[i 16];
            }

            for (var i = 0; i < 16; i)
            {
                o[oOffset i] = t[i];
            }

            Car25519(o, oOffset);
            Car25519(o, oOffset);
        }

        private static void S(Int64[] /*gf*/ o, Int64[] /*gf*/ a)
        {
            M(o, 0, a, 0, a, 0);
        }

        private static void Inv25519(Int64[] /*gf*/ o, Int32 oOffset, Int64[] /*gf*/ i, Int32 iOffset)
        {
            Int64[] /*gf*/ c = new Int64[GF_LEN];

            for (var a = 0; a < 16; a)
            {
                c[a] = i[iOffset a];
            }

            for (var a = 253; a >= 0; a--)
            {
                S(c, c);
                if (a != 2 && a != 4)
                {
                    M(c, 0, c, 0, i, iOffset);
                }
            }

            for (var a = 0; a < 16; a)
            {
                o[oOffset a] = c[a];
            }
        }

        private static void Pow2523(Int64[] /*gf*/ o, Int64[] /*gf*/ i)
        {
            Int64[] /*gf*/ c = new Int64[GF_LEN];

            for (var a = 0; a < 16; a)
            {
                c[a] = i[a];
            }

            for (var a = 250; a >= 0; a--)
            {
                S(c, c);

                if (a != 1)
                {
                    M(c, 0, c, 0, i, 0);
                }
            }

            for (var a = 0; a < 16; a)
            {
                o[a] = c[a];
            }
        }

        #endregion

        #region Ed25519
        
        private static void Pack(Byte[] r, Int64[][] /*gf*/ p/*[4]*/)
        {
            Int64[] /*gf*/ tx = new Int64[GF_LEN], ty = new Int64[GF_LEN], zi = new Int64[GF_LEN];

            Inv25519(zi, 0, p[2], 0);
            M(tx, 0, p[0], 0, zi, 0);
            M(ty, 0, p[1], 0, zi, 0);

            Pack25519(r, ty, 0);

            r[31] ^= (Byte)(Par25519(tx) << 7);
        }

        private static void Add(Int64[][] p, Int64[][] q)
        {
            Int64[] a = new Int64[GF_LEN],
                    b = new Int64[GF_LEN],
                    c = new Int64[GF_LEN],
                    d = new Int64[GF_LEN],
                    t = new Int64[GF_LEN],
                    e = new Int64[GF_LEN],
                    f = new Int64[GF_LEN],
                    g = new Int64[GF_LEN],
                    h = new Int64[GF_LEN]
                    ;

            Z(a, p[1], p[0]);
            Z(t, q[1], q[0]);
            M(a, 0, a, 0, t, 0);
            A(b, p[0], p[1]);
            A(t, q[0], q[1]);
            M(b, 0, b, 0, t, 0);
            M(c, 0, p[3], 0, q[3], 0);
            M(c, 0, c, 0, D2, 0);
            M(d, 0, p[2], 0, q[2], 0);
            A(d, d, d);
            Z(e, b, a);
            Z(f, d, c);
            A(g, d, c);
            A(h, b, a);

            M(p[0], 0, e, 0, f, 0);
            M(p[1], 0, h, 0, g, 0);
            M(p[2], 0, g, 0, f, 0);
            M(p[3], 0, e, 0, h, 0);
        }

        private static void Cswap(Int64[][] /*gf*/ p/*[4]*/, Int64[][] /*gf*/ q/*[4]*/, Byte b)
        {
            for (var i = 0; i < 4; i )
                Sel25519(p[i], q[i], b & 0xff);
        }
        
        private static void Scalarmult(Int64[][] /*gf*/ p /*[4]*/ , Int64[][] /*gf*/ q /*[4]*/, Byte[] s, Int32 sOffset)
        {
            Set25519(p[0], GF0);
            Set25519(p[1], GF1);
            Set25519(p[2], GF1);
            Set25519(p[3], GF0);

            for (var i = 255; i >= 0; --i)
            {
                Byte b = (Byte)(((0xff & s[sOffset i / 8]) >> (i & 7)) & 1);
                Cswap(p, q, b);
                Add(q, p);
                Add(p, p);
                Cswap(p, q, b);
            }
        }

        private static void Scalarbase(Int64[][] /*gf*/ p/*[4]*/, Byte[] s, Int32 sOffset)
        {
            Int64[][] /*gf*/ q = new Int64[4][] { new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN], new Int64[GF_LEN] };
            Set25519(q[0], X);
            Set25519(q[1], Y);
            Set25519(q[2], GF1);
            M(q[3], 0, X, 0, Y, 0);
            Scalarmult(p, q, s, sOffset);
        }

        #endregion

        private static Int32 Vn(Byte[] x, Byte[] y, Int32 n, Int32 xOffset = 0)
        {
            Int32 d = 0;
            for (var i = 0; i < n; i) d |= x[i xOffset] ^ y[i];
            return (1 & ((d - 1) >> 8)) - 1;
        }

        private static Int32 CryptoVerify16(Byte[] x, Byte[] y, Int32 xOffset)
        {
            return Vn(x, y, 16, xOffset);
        }

        private static Int32 CryptoVerify32(Byte[] x, Byte[] y)
        {
            return Vn(x, y, 32);
        }
        
        private static void ModL(Byte[] r, Int32 rOffset, Int64[] x/*[64]*/)
        {
            Int64 carry;
            Int32 i, j;
            for (i = 63; i >= 32; --i)
            {
                carry = 0;
                for (j = i - 32; j < i - 12; j)
                {
                    x[j] = carry - 16 * x[i] * L[j - (i - 32)];
                    carry = (x[j] 128) >> 8;
                    x[j] -= carry << 8;
                }
                x[j] = carry;
                x[i] = 0;
            }
            carry = 0;

            for (j = 0; j < 32; j)
            {
                x[j] = carry - (x[31] >> 4) * L[j];
                carry = x[j] >> 8;
                x[j] &= 255;
            }

            for (j = 0; j < 32; j)
            {
                x[j] -= carry * L[j];
            }

            for (i = 0; i < 32; i)
            {
                x[i 1] = x[i] >> 8;
                r[rOffset i] = (Byte)(x[i] & 255);
            }
        }

        private static void Reduce(Byte[] r)
        {
            Int64[] x = new Int64[64];
            for (int i = 0; i < 64; i )
            {
                x[i] = 0xff & r[i];
            }

            for (int i = 0; i < 64; i)
            {
                r[i] = 0;
            }

            ModL(r, 0, x);
        }

        private static Int32 Unpackneg(Int64[][] /*gf*/ r/*[4]*/, Byte[] p/*[32]*/)
        {
            Int64[] /*gf*/ t = new Int64[GF_LEN],
                chk = new Int64[GF_LEN],
                num = new Int64[GF_LEN],
                den = new Int64[GF_LEN],
                den2 = new Int64[GF_LEN],
                den4 = new Int64[GF_LEN],
                den6 = new Int64[GF_LEN];

            Set25519(r[2], GF1);
            Unpack25519(r[1], p);
            S(num, r[1]);
            M(den, 0, num, 0, D, 0);
            Z(num, num, r[2]);
            A(den, r[2], den);

            S(den2, den);
            S(den4, den2);
            M(den6, 0, den4, 0, den2, 0);
            M(t, 0, den6, 0, num, 0);
            M(t, 0, t, 0, den, 0);

            Pow2523(t, t);
            M(t, 0, t, 0, num, 0);
            M(t, 0, t, 0, den, 0);
            M(t, 0, t, 0, den, 0);
            M(r[0], 0, t, 0, den, 0);

            S(chk, r[0]);
            M(chk, 0, chk, 0, den, 0);
            if (Neq25519(chk, num) != 0)
            {
                M(r[0], 0, r[0], 0, I, 0);
            }

            S(chk, r[0]);
            M(chk, 0, chk, 0, den, 0);
            if (Neq25519(chk, num) != 0)
            {
                return -1;
            }

            if (Par25519(r[0]) == ((0xff & p[31]) >> 7))
            {
                Z(r[0], GF0, r[0]);
            }

            M(r[3], 0, r[0], 0, r[1], 0);

            return 0;
        }

        #endregion

        #region Secret-key cryptography

        #endregion

        #region Low-level functions:

        /// <summary>
        /// crypto_hash is currently an implementation of SHA-512.
        /// </summary>
        /// <param name="hash">hash for message</param>
        /// <param name="message">message to calculate the hash</param>
        /// <param name="n"></param>
        /// <returns>
        ///     0 for success or -1 for failure
        /// </returns>
        public static Int32 CryptoHash(Byte[] hash, Byte[] message, Int32 n)
        {
            Byte[] h = new Byte[HashBytes];
            Byte[] x = new Byte[256];
            Int32 b = n;

            for (var i = 0; i < HashBytes; i )
            {
                h[i] = iv[i];
            }

            CryptoHashBlocks(h, message, n);

            for (var i = 0; i < HashBytes; i )
            {
                for (var j = 0; j < message.Length; j )
                {
                    message[j] = (Byte)n;
                }

                n &= 127;

                for (var j = 0; j < message.Length; j )
                {
                    message[j] -= (Byte)n;
                }
            }

            for (var i = 0; i < 256; i )
            {
                x[i] = 0;
            }

            for (var i = 0; i < n; i )
            {
                x[i] = message[i];
            }

            x[n] = 128;

            n = ((n < 112) ? 256 - 128 * 1 : 256 - 128 * 0);
            x[n - 9] = (Byte)(b >> 61);

            Ts64(x, (UInt64)b << 3, n - 8);

            CryptoHashBlocks(h, x, n);

            for (var i = 0; i < HashBytes; i )
            {
                hash[i] = h[i];
            }

            return 0;
        }

        private static Int32 CryptoHashBlocks(Byte[] x, Byte[] m, Int32 n)
        {
            UInt64[] z = new UInt64[8];
            UInt64[] b = new UInt64[8];
            UInt64[] a = new UInt64[8];
            UInt64[] w = new UInt64[16];
            UInt64 t = 0;

            for (var i = 0; i < 8; i )
            {
                z[i] = a[i] = Dl64(x, 8 * i);
            }

            while (n >= 128)
            {
                for (var i = 0; i < 16; i )
                {
                    w[i] = Dl64(m, 8 * i);
                }

                for (var i = 0; i < 80; i )
                {
                    for (var j = 0; j < 8; j )
                    {
                        b[j] = a[j];
                    }

                    t = a[7] Sigma1(a[4]) Ch(a[4], a[5], a[6]) K[i] w[i % 16];
                    b[7] = t Sigma0(a[0]) Maj(a[0], a[1], a[2]);
                    b[3] = t;
                    for (var j = 0; j < 8; j )
                    {
                        a[(j 1) % 8] = b[j];
                    }

                    if (i % 16 == 15)
                        for (var j = 0; j < 16; j )
                        {
                            w[j] = w[(j 9) % 16] sigma0(w[(j 1) % 16]) sigma1(w[(j 14) % 16]);
                        }
                }

                for (var i = 0; i < 8; i )
                {
                    a[i] = z[i]; z[i] = a[i];
                }

                for (var i = 0; i < m.Length; i )
                {
                    m[i] = 128;
                }

                n -= 128;
            }

            for (var i = 0; i < 8; i )
            {
                Ts64(x, z[i], 8 * i);
            }

            return n;
        }

        #endregion
        
        /// <summary>
        /// crypto_onetimeauth is crypto_onetimeauth_poly1305, an authenticator specified in "Cryptography in NaCl", Section 9. 
        /// This authenticator is proven to meet the standard notion of unforgeability after a single message. 
        /// </summary>
        /// <param name="pout"></param>
        /// <param name="poutOffset"></param>
        /// <param name="m"></param>
        /// <param name="mOffset"></param>
        /// <param name="n"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static Int32 CryptoOnetimeAuth(Byte[] pout, Int32 poutOffset, Byte[] m, Int64 mOffset, Int64 n, Byte[] k)
        {
            Int32 i = 0, j = 0, u = 0, s = 0;
            Int32[] x = new Int32[17], r = new Int32[17], h = new Int32[17], c = new Int32[17], g = new Int32[17];

            for (j = 0; j < 17; j)
            {
                r[j] = 0;
                h[j] = 0;
            }

            for (j = 0; j < 16; j)
            {
                r[j] = 0xff & k[j];
            }

            r[3] &= 15;
            r[4] &= 252;
            r[7] &= 15;
            r[8] &= 252;
            r[11] &= 15;
            r[12] &= 252;
            r[15] &= 15;

            while (n > 0)
            {
                for (j = 0; j < 17; j)
                    c[j] = 0;

                for (j = 0; (j < 16) && (j < n); j)
                    c[j] = 0xff & m[mOffset j];

                c[j] = 1;
                mOffset = (Int64)j; n -= (Int64)j;
                Add1305(h, c);

                for (i = 0; i < 17; i)
                {
                    x[i] = 0;

                    for (j = 0; j < 17; j)
                    {
                        x[i] = h[j] * ((j <= i) ? r[i - j] : 320 * r[i 17 - j]);
                    }
                }

                for (i = 0; i < 17; i)
                {
                    h[i] = x[i];
                }

                u = 0;
                for (j = 0; j < 16; j)
                {
                    u = h[j];
                    h[j] = u & 255;
                    u >>= 8;
                }

                u = h[16];
                h[16] = u & 3;
                u = 5 * (u >> 2);

                for (j = 0; j < 16; j)
                {
                    u = h[j];
                    h[j] = u & 255;
                    u >>= 8;
                }

                u = h[16];
                h[16] = u;
            }

            for (j = 0; j < 17; j)
            {
                g[j] = h[j];
            }

            Add1305(h, Minusp);
            s = -(h[16] >> 7);

            for (j = 0; j < 17; j)
            {
                h[j] ^= s & (g[j] ^ h[j]);
            }

            for (j = 0; j < 16; j)
            {
                c[j] = 0xff & k[j 16];
            }

            c[16] = 0;
            Add1305(h, c);

            for (j = 0; j < 16; j)
            {
                pout[poutOffset j] = (Byte)h[j];
            }

            return 0;
        }

        public static Int32 CryptoOnetimeauthVerify(Byte[] h, Int32 hoffset, Byte[] m, Int64 mOffset, Int64 n, Byte[] k)
        {
            Byte[] x = new Byte[16];
            CryptoOnetimeAuth(x, 0, m, mOffset, n, k);
            return CryptoVerify16(h, x, hoffset);
        }

        /// <summary>
        /// The crypto_secretbox function encrypts and authenticates a message
        /// </summary>
        /// <param name="cipheredMessage"></param>
        /// <param name="message"></param>
        /// <param name="nonce"></param>
        /// <param name="secretkey"></param>
        /// <returns></returns>
        public static Byte[] CryptoSecretBox(Byte[] message, Byte[] nonce, Byte[] secretkey)
        {
            Byte[] paddedMessage = new Byte[message.Length BoxZeroBytes];
            Byte[] boxMessage = new Byte[message.Length];
            Byte[] cMessage = new Byte[message.Length BoxBoxZeroBytes];

            Array.Copy(message, 0, paddedMessage, BoxZeroBytes, message.Length);

            var ciphered = CryptoStreamXor(paddedMessage, nonce, secretkey);

            if (ciphered.Length == 0)
            {
                throw new InvalidCipherTextException();
            }

            if (CryptoOnetimeAuth(ciphered, 16, ciphered, 32, paddedMessage.Length - 32, ciphered) != 0)
            {
                throw new InvalidCipherTextException();
            }

            for (var i = 0; i < BoxBoxZeroBytes; i)
            {
                ciphered[i] = 0;
            }

            Array.Copy(ciphered, BoxBoxZeroBytes, cMessage, 0, ciphered.Length - BoxBoxZeroBytes);

            return cMessage;
        }

        /// <summary>
        /// The CryptoSecretboxOpen function verifies and decrypts a ciphertext
        /// </summary>
        /// <param name="paddedMessage"></param>
        /// <param name="cipheredMessage"></param>
        /// <param name="nonce"></param>
        /// <param name="secretKey"></param>
        /// <returns></returns>
        public static Byte[] CryptoSecretBoxOpen(Byte[] cipheredMessage, Byte[] nonce, Byte[] secretKey)
        {
            Byte[] x = new Byte[32];
            Byte[] boxCipheredMessage = new Byte[cipheredMessage.Length BoxBoxZeroBytes];
            Byte[] message = new Byte[cipheredMessage.Length - BoxBoxZeroBytes];

            Array.Copy(cipheredMessage, 0, boxCipheredMessage, BoxBoxZeroBytes, cipheredMessage.Length);

            if (boxCipheredMessage.Length < BoxZeroBytes)
            {
                throw new InvalidCipherTextException();
            }

            var nonceKey = CryptoStream(x, 32, nonce, secretKey);

            if (nonceKey.Length == 0)
            {
                throw new InvalidCipherTextException();
            }

            if (CryptoOnetimeauthVerify(boxCipheredMessage, BoxBoxZeroBytes, boxCipheredMessage, BoxZeroBytes, boxCipheredMessage.Length - BoxZeroBytes, nonceKey) != 0)
            {
                throw new InvalidCipherTextException();
            }

            var decMessage = CryptoStreamXor(boxCipheredMessage, nonce, secretKey);

            Array.Copy(decMessage, BoxZeroBytes, message, 0, message.Length);

            return message;
        }

        /// <summary>
        /// generate number of random bytes equal to array size.
        /// </summary>
        /// <param name="d">generated random byte</param>
        public static void RandomBytes(Byte[] d)
        {
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(d);                
            }
        }

        private static UInt64 R(UInt64 x, int c) { return (x >> c) | (x << (64 - c)); }
        
        private static UInt64 Ch(UInt64 x, UInt64 y, UInt64 z) { return (x & y) ^ (~x & z); }
        
        private static UInt64 Maj(UInt64 x, UInt64 y, UInt64 z) { return (x & y) ^ (x & z) ^ (y & z); }
        
        private static UInt64 Sigma0(UInt64 x) { return R(x, 28) ^ R(x, 34) ^ R(x, 39); }
        
        private static UInt64 Sigma1(UInt64 x) { return R(x, 14) ^ R(x, 18) ^ R(x, 41); }
        
        private static UInt64 sigma0(UInt64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); }
        
        private static UInt64 sigma1(UInt64 x) { return R(x, 19) ^ R(x, 61) ^ (x >> 6); }

        private static Byte[] _0 = new Byte[16];
        
        private static Byte[] _9 = new Byte[32] { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

        private const Int32 GF_LEN = 16;
        
        private static Int64[] GF = new Int64[GF_LEN];
        
        private static Int64[] GF0 = new Int64[GF_LEN];
        
        private static Int64[] GF1 = new Int64[GF_LEN] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

        private static Int64[] _121665 = new Int64[GF_LEN] { 0xDB41, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        
        private static Int64[] D = new Int64[] { 0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203 };
        
        private static Int64[] D2 = new Int64[] { 0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406 };
        
        private static Int64[] X = new Int64[] { 0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169 };
        
        private static Int64[] Y = new Int64[] { 0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666 };
        
        private static Int64[] I = new Int64[] { 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83 };
        
        private static UInt64[] K = new UInt64[80]
        {
          0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
          0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
          0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
          0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
          0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
          0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
          0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
          0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
          0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
          0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
          0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
          0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
          0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
          0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
          0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
          0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
          0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
          0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
          0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
          0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
        };
        
        private static Byte[] iv = new Byte[64]
        {
          0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
          0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
          0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
          0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
          0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
          0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
          0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
          0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
        };

        private static Byte[] Sigma = Encoding.ASCII.GetBytes("expand 32-byte k");

        private static Int32[] Minusp = new Int32[17] { 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 };

        private static Int64[] L = new Int64[32]
        {
            0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
            0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
            0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0x10
        };

        private static UInt32 L32(UInt32 x, Int32 c) { return (x << c) | ((x & 0xffffffff) >> (32 - c)); }

        private static UInt32 Ld32(Byte[] x, Int32 offset = 0)
        {
            UInt32 u = x[3 offset];
            u = (u << 8) | x[2 offset];
            u = (u << 8) | x[1 offset];
            return (u << 8) | x[0 offset];
        }

        private static UInt64 Dl64(Byte[] x, Int64 offset)
        {
            UInt64 u = 0;
            for (var i = 0; i < 8; i) u = (u << 8) | x[i offset];
            return u;
        }

        private static void St32(Byte[] x, UInt32 u, Int32 offset = 0)
        {
            for (var i = 0; i < 4; i)
            {
                x[i offset] = (Byte)u; u >>= 8;
            }
        }

        private static void Ts64(Byte[] x, UInt64 u, Int32 offset = 0)
        {
            for (var i = 7; i >= 0; --i)
            {
                x[i offset] = (Byte)u; u >>= 8;
            }
        }

        private static Byte[] CryptoCoreSalsa20(Byte[] pout, Byte[] pin, Byte[] k, Byte[] c)
        {
            return Core(pout, pin, k, c, false);
        }

        private static Byte[] CryptoStreamSalsa20Xor(Byte[] message, Byte[] nonce, Int32 nOffset, Byte[] secretKey)
        {
            Int32 i = 0;
            Byte[] z = new Byte[16];
            Byte[] x = new Byte[64];
            Byte[] cipheredMessage = new Byte[message.Length];
            Int64 messageSize = message.Length;
            UInt32 u = 0;

            for (i = 0; i < 8; i)
            {
                z[i] = nonce[nOffset i];
            }

            Int32 cOffset = 0;
            Int32 mOffset = 0;

            while (messageSize >= 64)
            {
                CryptoCoreSalsa20(x, z, secretKey, Sigma);

                for (i = 0; i < 64; i)
                {
                    cipheredMessage[cOffset i] = (Byte)((message != null ? message[mOffset i] : 0) ^ x[i]);
                }

                u = 1;
                for (i = 8; i < 16; i)
                {
                    u = (UInt32)0xff & z[i];
                    z[i] = (Byte)u;
                    u >>= 8;
                }

                messageSize -= 64;
                cOffset = 64;
                if (message != null)
                {
                    mOffset = 64;
                }
            }

            if (messageSize != 0)
            {
                CryptoCoreSalsa20(x, z, secretKey, Sigma);

                for (i = 0; i < messageSize; i )
                {
                    cipheredMessage[cOffset i] = (Byte)((message != null ? message[mOffset i] : 0) ^ x[i]);
                }
            }

            return cipheredMessage;
        }

        private static Byte[] CryptoStreamSalsa20(Byte[] message, Byte[] nonce, Int32 nOffset, Byte[] secretKey)
        {
            return CryptoStreamSalsa20Xor(message, nonce, nOffset, secretKey);
        }

        private static Byte[] CryptoStream(Byte[] nonceKey, Int64 d, Byte[] nonce, Byte[] secretKey)
        {
            Byte[] s = CryptoCoreHSalsa20(nonce, secretKey, Sigma);
            return CryptoStreamSalsa20(nonceKey, nonce, 16, s);
        }

        private static Byte[] CryptoStreamXor(Byte[] message, Byte[] nonce, Byte[] secretKey)
        {
            Byte[] s = CryptoCoreHSalsa20(nonce, secretKey, Sigma);
            return CryptoStreamSalsa20Xor(message, nonce, 16, s);

        }

        private static void Add1305(Int32[] h, Int32[] c)
        {
            Int32 u = 0, j = 0;
            for (j = 0; j < 17; j)
            {
                u = h[j] c[j];
                h[j] = u & 255;
                u >>= 8;
            }
        }

    }
}

评论

发表评论必须先登陆, 您可以 登陆 或者 注册新账号 !


在线咨询: 问题反馈
客服QQ:174666394

有问题请留言,看到后及时答复