| | | 1 | | using System; |
| | | 2 | | using Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10; |
| | | 3 | | |
| | | 4 | | namespace Renci.SshNet.Security.Chaos.NaCl |
| | | 5 | | { |
| | | 6 | | internal static class Ed25519 |
| | | 7 | | { |
| | 4 | 8 | | public static readonly int PublicKeySizeInBytes = 32; |
| | 4 | 9 | | public static readonly int SignatureSizeInBytes = 64; |
| | 4 | 10 | | public static readonly int ExpandedPrivateKeySizeInBytes = 32 * 2; |
| | 4 | 11 | | public static readonly int PrivateKeySeedSizeInBytes = 32; |
| | 4 | 12 | | public static readonly int SharedKeySizeInBytes = 32; |
| | | 13 | | |
| | | 14 | | public static bool Verify(ArraySegment<byte> signature, ArraySegment<byte> message, ArraySegment<byte> publicKey |
| | 0 | 15 | | { |
| | 0 | 16 | | if (signature.Count != SignatureSizeInBytes) |
| | 0 | 17 | | throw new ArgumentException(string.Format("Signature size must be {0}", SignatureSizeInBytes), "signatur |
| | 0 | 18 | | if (publicKey.Count != PublicKeySizeInBytes) |
| | 0 | 19 | | throw new ArgumentException(string.Format("Public key size must be {0}", PublicKeySizeInBytes), "publicK |
| | 0 | 20 | | return Ed25519Operations.crypto_sign_verify(signature.Array, signature.Offset, message.Array, message.Offset |
| | 0 | 21 | | } |
| | | 22 | | |
| | | 23 | | public static bool Verify(byte[] signature, byte[] message, byte[] publicKey) |
| | 3 | 24 | | { |
| | 3 | 25 | | if (signature == null) |
| | 0 | 26 | | throw new ArgumentNullException("signature"); |
| | 3 | 27 | | if (message == null) |
| | 0 | 28 | | throw new ArgumentNullException("message"); |
| | 3 | 29 | | if (publicKey == null) |
| | 0 | 30 | | throw new ArgumentNullException("publicKey"); |
| | 3 | 31 | | if (signature.Length != SignatureSizeInBytes) |
| | 0 | 32 | | throw new ArgumentException(string.Format("Signature size must be {0}", SignatureSizeInBytes), "signatur |
| | 3 | 33 | | if (publicKey.Length != PublicKeySizeInBytes) |
| | 0 | 34 | | throw new ArgumentException(string.Format("Public key size must be {0}", PublicKeySizeInBytes), "publicK |
| | 3 | 35 | | return Ed25519Operations.crypto_sign_verify(signature, 0, message, 0, message.Length, publicKey, 0); |
| | 3 | 36 | | } |
| | | 37 | | |
| | | 38 | | public static void Sign(ArraySegment<byte> signature, ArraySegment<byte> message, ArraySegment<byte> expandedPri |
| | 1 | 39 | | { |
| | 1 | 40 | | if (signature.Array == null) |
| | 0 | 41 | | throw new ArgumentNullException("signature.Array"); |
| | 1 | 42 | | if (signature.Count != SignatureSizeInBytes) |
| | 0 | 43 | | throw new ArgumentException("signature.Count"); |
| | 1 | 44 | | if (expandedPrivateKey.Array == null) |
| | 0 | 45 | | throw new ArgumentNullException("expandedPrivateKey.Array"); |
| | 1 | 46 | | if (expandedPrivateKey.Count != ExpandedPrivateKeySizeInBytes) |
| | 0 | 47 | | throw new ArgumentException("expandedPrivateKey.Count"); |
| | 1 | 48 | | if (message.Array == null) |
| | 0 | 49 | | throw new ArgumentNullException("message.Array"); |
| | 1 | 50 | | Ed25519Operations.crypto_sign2(signature.Array, signature.Offset, message.Array, message.Offset, message.Cou |
| | 1 | 51 | | } |
| | | 52 | | |
| | | 53 | | public static byte[] Sign(byte[] message, byte[] expandedPrivateKey) |
| | 1 | 54 | | { |
| | 1 | 55 | | var signature = new byte[SignatureSizeInBytes]; |
| | 1 | 56 | | Sign(new ArraySegment<byte>(signature), new ArraySegment<byte>(message), new ArraySegment<byte>(expandedPriv |
| | 1 | 57 | | return signature; |
| | 1 | 58 | | } |
| | | 59 | | |
| | | 60 | | public static byte[] PublicKeyFromSeed(byte[] privateKeySeed) |
| | 0 | 61 | | { |
| | | 62 | | byte[] privateKey; |
| | | 63 | | byte[] publicKey; |
| | 0 | 64 | | KeyPairFromSeed(out publicKey, out privateKey, privateKeySeed); |
| | 0 | 65 | | CryptoBytes.Wipe(privateKey); |
| | 0 | 66 | | return publicKey; |
| | 0 | 67 | | } |
| | | 68 | | |
| | | 69 | | public static byte[] ExpandedPrivateKeyFromSeed(byte[] privateKeySeed) |
| | 0 | 70 | | { |
| | | 71 | | byte[] privateKey; |
| | | 72 | | byte[] publicKey; |
| | 0 | 73 | | KeyPairFromSeed(out publicKey, out privateKey, privateKeySeed); |
| | 0 | 74 | | CryptoBytes.Wipe(publicKey); |
| | 0 | 75 | | return privateKey; |
| | 0 | 76 | | } |
| | | 77 | | |
| | | 78 | | public static void KeyPairFromSeed(out byte[] publicKey, out byte[] expandedPrivateKey, byte[] privateKeySeed) |
| | 7 | 79 | | { |
| | 7 | 80 | | if (privateKeySeed == null) |
| | 0 | 81 | | throw new ArgumentNullException("privateKeySeed"); |
| | 7 | 82 | | if (privateKeySeed.Length != PrivateKeySeedSizeInBytes) |
| | 0 | 83 | | throw new ArgumentException("privateKeySeed"); |
| | 7 | 84 | | var pk = new byte[PublicKeySizeInBytes]; |
| | 7 | 85 | | var sk = new byte[ExpandedPrivateKeySizeInBytes]; |
| | 7 | 86 | | Ed25519Operations.crypto_sign_keypair(pk, 0, sk, 0, privateKeySeed, 0); |
| | 7 | 87 | | publicKey = pk; |
| | 7 | 88 | | expandedPrivateKey = sk; |
| | 7 | 89 | | } |
| | | 90 | | |
| | | 91 | | public static void KeyPairFromSeed(ArraySegment<byte> publicKey, ArraySegment<byte> expandedPrivateKey, ArraySeg |
| | 0 | 92 | | { |
| | 0 | 93 | | if (publicKey.Array == null) |
| | 0 | 94 | | throw new ArgumentNullException("publicKey.Array"); |
| | 0 | 95 | | if (expandedPrivateKey.Array == null) |
| | 0 | 96 | | throw new ArgumentNullException("expandedPrivateKey.Array"); |
| | 0 | 97 | | if (privateKeySeed.Array == null) |
| | 0 | 98 | | throw new ArgumentNullException("privateKeySeed.Array"); |
| | 0 | 99 | | if (publicKey.Count != PublicKeySizeInBytes) |
| | 0 | 100 | | throw new ArgumentException("publicKey.Count"); |
| | 0 | 101 | | if (expandedPrivateKey.Count != ExpandedPrivateKeySizeInBytes) |
| | 0 | 102 | | throw new ArgumentException("expandedPrivateKey.Count"); |
| | 0 | 103 | | if (privateKeySeed.Count != PrivateKeySeedSizeInBytes) |
| | 0 | 104 | | throw new ArgumentException("privateKeySeed.Count"); |
| | 0 | 105 | | Ed25519Operations.crypto_sign_keypair( |
| | 0 | 106 | | publicKey.Array, publicKey.Offset, |
| | 0 | 107 | | expandedPrivateKey.Array, expandedPrivateKey.Offset, |
| | 0 | 108 | | privateKeySeed.Array, privateKeySeed.Offset); |
| | 0 | 109 | | } |
| | | 110 | | |
| | | 111 | | [Obsolete("Needs more testing")] |
| | | 112 | | public static byte[] KeyExchange(byte[] publicKey, byte[] privateKey) |
| | 0 | 113 | | { |
| | 0 | 114 | | var sharedKey = new byte[SharedKeySizeInBytes]; |
| | 0 | 115 | | KeyExchange(new ArraySegment<byte>(sharedKey), new ArraySegment<byte>(publicKey), new ArraySegment<byte>(pri |
| | 0 | 116 | | return sharedKey; |
| | 0 | 117 | | } |
| | | 118 | | |
| | | 119 | | [Obsolete("Needs more testing")] |
| | | 120 | | public static void KeyExchange(ArraySegment<byte> sharedKey, ArraySegment<byte> publicKey, ArraySegment<byte> pr |
| | 0 | 121 | | { |
| | 0 | 122 | | if (sharedKey.Array == null) |
| | 0 | 123 | | throw new ArgumentNullException("sharedKey.Array"); |
| | 0 | 124 | | if (publicKey.Array == null) |
| | 0 | 125 | | throw new ArgumentNullException("publicKey.Array"); |
| | 0 | 126 | | if (privateKey.Array == null) |
| | 0 | 127 | | throw new ArgumentNullException("privateKey"); |
| | 0 | 128 | | if (sharedKey.Count != 32) |
| | 0 | 129 | | throw new ArgumentException("sharedKey.Count != 32"); |
| | 0 | 130 | | if (publicKey.Count != 32) |
| | 0 | 131 | | throw new ArgumentException("publicKey.Count != 32"); |
| | 0 | 132 | | if (privateKey.Count != 64) |
| | 0 | 133 | | throw new ArgumentException("privateKey.Count != 64"); |
| | | 134 | | |
| | | 135 | | FieldElement montgomeryX, edwardsY, edwardsZ, sharedMontgomeryX; |
| | 0 | 136 | | FieldOperations.fe_frombytes(out edwardsY, publicKey.Array, publicKey.Offset); |
| | 0 | 137 | | FieldOperations.fe_1(out edwardsZ); |
| | 0 | 138 | | MontgomeryCurve25519.EdwardsToMontgomeryX(out montgomeryX, ref edwardsY, ref edwardsZ); |
| | 0 | 139 | | byte[] h = Sha512.Hash(privateKey.Array, privateKey.Offset, 32);//ToDo: Remove alloc |
| | 0 | 140 | | ScalarOperations.sc_clamp(h, 0); |
| | 0 | 141 | | MontgomeryOperations.scalarmult(out sharedMontgomeryX, h, 0, ref montgomeryX); |
| | 0 | 142 | | CryptoBytes.Wipe(h); |
| | 0 | 143 | | FieldOperations.fe_tobytes(sharedKey.Array, sharedKey.Offset, ref sharedMontgomeryX); |
| | 0 | 144 | | MontgomeryCurve25519.KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset); |
| | 0 | 145 | | } |
| | | 146 | | } |
| | | 147 | | } |