20
|
1 ???using System; |
|
2 using curve25519xsalsa20poly1305impl = UCIS.NaCl.crypto_box.curve25519xsalsa20poly1305; |
|
3 using edwards25519sha512batchimpl = UCIS.NaCl.crypto_sign.edwards25519sha512batch; |
|
4 using xsalsa20poly1305impl = UCIS.NaCl.crypto_secretbox.xsalsa20poly1305; |
|
5 |
|
6 namespace UCIS.NaCl.v2 { |
|
7 public class curve25519keypair { |
|
8 private Byte[] publickey, secretkey; |
|
9 |
|
10 public curve25519keypair() { |
|
11 curve25519xsalsa20poly1305impl.crypto_box_keypair(out publickey, out secretkey); |
|
12 } |
|
13 public curve25519keypair(Byte[] secretkey) { |
|
14 this.publickey = curve25519xsalsa20poly1305impl.crypto_box_getpublickey(secretkey); |
|
15 this.secretkey = secretkey; |
|
16 } |
|
17 public curve25519keypair(Byte[] secretkey, Byte[] publickey) { |
|
18 if (publickey.Length != curve25519xsalsa20poly1305impl.PUBLICKEYBYTES) throw new ArgumentOutOfRangeException("publickey"); |
|
19 if (secretkey.Length != curve25519xsalsa20poly1305impl.SECRETKEYBYTES) throw new ArgumentOutOfRangeException("secretkey"); |
|
20 this.secretkey = secretkey; |
|
21 this.publickey = publickey; |
|
22 } |
|
23 public Byte[] PublicKey { get { return publickey; } } |
|
24 public Byte[] SecretKey { get { return secretkey; } } |
|
25 } |
|
26 public class curve25519xsalsa20poly1305 : xsalsa20poly1305 { |
|
27 public curve25519xsalsa20poly1305(Byte[] publickey, curve25519keypair secretkey) |
|
28 : this(publickey, secretkey.SecretKey) { |
|
29 } |
|
30 public curve25519xsalsa20poly1305(Byte[] publickey, Byte[] secretkey) |
|
31 : base(curve25519xsalsa20poly1305impl.crypto_box_beforenm(publickey, secretkey)) { |
|
32 } |
|
33 } |
|
34 public class xsalsa20poly1305 { |
|
35 Byte[] sharedkey; |
|
36 Byte[] nonce; |
|
37 |
|
38 public int SharedKeySize { get { return xsalsa20poly1305impl.KEYBYTES; } } |
|
39 |
|
40 public xsalsa20poly1305(Byte[] sharedkey) : this(sharedkey, null) { } |
|
41 public xsalsa20poly1305(Byte[] sharedkey, Byte[] nonce) { |
|
42 if (ReferenceEquals(sharedkey, null)) throw new ArgumentNullException("secretkey"); |
|
43 if (sharedkey.Length != xsalsa20poly1305impl.KEYBYTES) throw new ArgumentOutOfRangeException("secretkey", "The key size does not match the expected key length"); |
|
44 this.sharedkey = sharedkey; |
|
45 this.nonce = new Byte[xsalsa20poly1305impl.NONCEBYTES]; |
|
46 if (!ReferenceEquals(nonce, null)) this.Nonce = nonce; |
|
47 } |
|
48 |
|
49 public Byte[] Nonce { |
|
50 get { return this.nonce; } |
|
51 set { |
|
52 if (ReferenceEquals(value, null)) throw new ArgumentNullException("value"); |
|
53 if (value.Length > xsalsa20poly1305impl.NONCEBYTES) throw new ArgumentOutOfRangeException("value", "Nonce is too big"); |
|
54 value.CopyTo(nonce, 0); |
|
55 Array.Clear(this.nonce, value.Length, this.nonce.Length - value.Length); |
|
56 } |
|
57 } |
|
58 |
|
59 public Byte[] SharedKey { |
|
60 get { return sharedkey; } |
|
61 } |
|
62 |
|
63 public unsafe Byte[] Encrypt(Byte[] data) { |
|
64 return Encrypt(data, 0, data.Length); |
|
65 } |
|
66 public unsafe Byte[] Encrypt(Byte[] data, int offset, int count) { |
|
67 if (ReferenceEquals(data, null)) throw new ArgumentNullException("data"); |
|
68 if (offset < 0) throw new ArgumentOutOfRangeException("offset", "Offset can not be negative"); |
|
69 if (data.Length < offset + count) throw new ArgumentOutOfRangeException("count", "The specified range is outside of the array"); |
|
70 Byte[] ret = new Byte[GetEncryptedSize(count)]; |
|
71 fixed (Byte* mp = data, cp = ret, np = nonce, kp = sharedkey) { |
|
72 if (xsalsa20poly1305impl.crypto_secretbox_nopad(cp, mp + offset, (ulong)count, np, kp) != 0) throw new InvalidOperationException("Encryption failed"); |
|
73 } |
|
74 return ret; |
|
75 } |
|
76 public unsafe int EncryptTo(Byte[] data, int offset, int count, Byte[] outdata, int outoffset, int outcount) { |
|
77 if (ReferenceEquals(data, null)) throw new ArgumentNullException("data"); |
|
78 if (offset < 0) throw new ArgumentOutOfRangeException("offset", "Offset can not be negative"); |
|
79 if (data.Length < offset + count) throw new ArgumentOutOfRangeException("count", "The specified range is outside of the array"); |
|
80 if (ReferenceEquals(outdata, null)) throw new ArgumentNullException("outdata"); |
|
81 if (outoffset < 0) throw new ArgumentOutOfRangeException("outoffset", "Offset can not be negative"); |
|
82 if (outdata.Length < outoffset + outcount) throw new ArgumentOutOfRangeException("outcount", "The specified range is outside of the array"); |
|
83 int retcount = GetEncryptedSize(count); |
|
84 if (outcount < retcount) throw new ArgumentOutOfRangeException("outcount", "The output buffer is too small"); |
|
85 fixed (Byte* mp = data, cp = outdata, np = nonce, kp = sharedkey) { |
|
86 if (xsalsa20poly1305impl.crypto_secretbox_nopad(cp + outoffset, mp + offset, (ulong)count, np, kp) != 0) throw new InvalidOperationException("Encryption failed"); |
|
87 } |
|
88 return outcount; |
|
89 } |
|
90 /*public unsafe void EncryptInplace(Byte[] data, int offset, int count) { |
|
91 if (ReferenceEquals(data, null)) throw new ArgumentNullException("data"); |
|
92 if (offset < 0) throw new ArgumentOutOfRangeException("offset", "Offset can not be negative"); |
|
93 if (data.Length < offset + count) throw new ArgumentOutOfRangeException("count", "The specified range is outside of the array"); |
|
94 if (count < 16) throw new ArgumentOutOfRangeException("count", "count should be at least 16"); |
|
95 fixed (Byte* mp = data, np = nonce, kp = sharedkey) { |
|
96 if (xsalsa20poly1305impl.crypto_secretbox_inplace_nopad(mp + offset, (ulong)count, np, kp) != 0) throw new InvalidOperationException("Encryption failed"); |
|
97 } |
|
98 }*/ |
|
99 public int GetEncryptedSize(int size) { |
|
100 return size + 16; |
|
101 } |
|
102 |
|
103 public unsafe Byte[] Decrypt(Byte[] data) { |
|
104 return Decrypt(data, 0, data.Length); |
|
105 } |
|
106 public unsafe Byte[] Decrypt(Byte[] data, int offset, int count) { |
|
107 if (ReferenceEquals(data, null)) throw new ArgumentNullException("data"); |
|
108 if (offset < 0) throw new ArgumentOutOfRangeException("offset", "Offset can not be negative"); |
|
109 if (data.Length < offset + count) throw new ArgumentOutOfRangeException("count", "The specified range is outside of the array"); |
|
110 if (count < 16) return null; |
|
111 Byte[] ret = new Byte[GetDecryptedSize(count)]; |
|
112 fixed (Byte* cp = data, mp = ret, np = nonce, kp = sharedkey) { |
|
113 if (xsalsa20poly1305impl.crypto_secretbox_open_nopad(mp, cp + offset, (ulong)count, np, kp) != 0) return null; |
|
114 } |
|
115 return ret; |
|
116 } |
|
117 public unsafe int? DecryptTo(Byte[] data, int offset, int count, Byte[] outdata, int outoffset, int outcount) { |
|
118 if (ReferenceEquals(data, null)) throw new ArgumentNullException("data"); |
|
119 if (offset < 0) throw new ArgumentOutOfRangeException("offset", "Offset can not be negative"); |
|
120 if (data.Length < offset + count) throw new ArgumentOutOfRangeException("count", "The specified range is outside of the array"); |
|
121 if (count < 16) return null; |
|
122 if (ReferenceEquals(outdata, null)) throw new ArgumentNullException("outdata"); |
|
123 if (outoffset < 0) throw new ArgumentOutOfRangeException("outoffset", "Offset can not be negative"); |
|
124 if (outdata.Length < outoffset + outcount) throw new ArgumentOutOfRangeException("outcount", "The specified range is outside of the array"); |
|
125 int retcount = GetDecryptedSize(count); |
|
126 if (outcount < retcount) throw new ArgumentOutOfRangeException("outcount", "The output buffer is too small"); |
|
127 fixed (Byte* cp = data, mp = outdata, np = nonce, kp = sharedkey) { |
|
128 if (xsalsa20poly1305impl.crypto_secretbox_open_nopad(mp + outoffset, cp + offset, (ulong)count, np, kp) != 0) return null; |
|
129 } |
|
130 return retcount; |
|
131 } |
|
132 public unsafe ArraySegment<Byte>? DecryptInplace(Byte[] data, int offset, int count) { |
|
133 if (ReferenceEquals(data, null)) throw new ArgumentNullException("data"); |
|
134 if (offset < 0) throw new ArgumentOutOfRangeException("offset", "Offset can not be negative"); |
|
135 if (data.Length < offset + count) throw new ArgumentOutOfRangeException("count", "The specified range is outside of the array"); |
|
136 if (count < 16) return null; |
|
137 fixed (Byte* cp = data, np = nonce, kp = sharedkey) { |
|
138 if (xsalsa20poly1305impl.crypto_secretbox_open_inplace_nopad(cp + offset, (ulong)count, np, kp) != 0) return null; |
|
139 } |
|
140 return new ArraySegment<byte>(data, offset + 16, count - 16); |
|
141 } |
|
142 public int GetDecryptedSize(int size) { |
|
143 if (size < 16) return -1; |
|
144 return size - 16; |
|
145 } |
|
146 |
|
147 public Boolean Verify(Byte[] data) { |
|
148 return Verify(data, 0, data.Length); |
|
149 } |
|
150 public unsafe Boolean Verify(Byte[] data, int offset, int count) { |
|
151 if (ReferenceEquals(data, null)) throw new ArgumentNullException("data"); |
|
152 if (offset < 0) throw new ArgumentOutOfRangeException("offset", "Offset can not be negative"); |
|
153 if (data.Length < offset + count) throw new ArgumentOutOfRangeException("count", "The specified range is outside of the array"); |
|
154 if (count < 16) return false; |
|
155 Byte[] ret = new Byte[GetDecryptedSize(count)]; |
|
156 fixed (Byte* cp = data, np = nonce, kp = sharedkey) { |
|
157 return xsalsa20poly1305impl.crypto_secretbox_verify(cp + offset, (ulong)count, np, kp); |
|
158 } |
|
159 } |
|
160 |
|
161 public Byte[] GenerateRandomNonce() { |
|
162 randombytes.generate(nonce); |
|
163 return nonce; |
|
164 } |
|
165 public void IncrementNonceLE() { |
|
166 for (int i = 0; i < nonce.Length && ++nonce[i] == 0; i++) ; |
|
167 } |
|
168 public void IncrementNonceBE() { |
|
169 for (int i = nonce.Length - 1; i >= 0 && ++nonce[i] == 0; i--) ; |
|
170 } |
|
171 |
|
172 public xsalsa20poly1305 Clone() { |
|
173 return new xsalsa20poly1305(sharedkey, nonce); |
|
174 } |
|
175 } |
|
176 public class edwards25519sha512batch { |
|
177 public Byte[] Sign(Byte[] message, Byte[] secretkey) { |
|
178 return edwards25519sha512batchimpl.crypto_sign(message, secretkey); |
|
179 } |
|
180 public int GetSignedSize(int size) { |
|
181 return size + 64; |
|
182 } |
|
183 public Byte[] Open(Byte[] signed, Byte[] publickey) { |
|
184 return edwards25519sha512batchimpl.crypto_sign_open(signed, publickey); |
|
185 } |
|
186 public unsafe Boolean Verify(Byte[] signed, Byte[] publickey) { |
|
187 if (publickey.Length != edwards25519sha512batchimpl.PUBLICKEYBYTES) throw new ArgumentException("publickey.Length != PUBLICKEYBYTES"); |
|
188 UInt64 mlen; |
|
189 fixed (Byte* smp = signed, pkp = publickey) return edwards25519sha512batchimpl.crypto_sign_open(null, out mlen, smp, (ulong)signed.Length, pkp) == 0; |
|
190 } |
|
191 public Byte[] Extract(Byte[] signed) { |
|
192 if (signed.Length < 64) return null; |
|
193 Byte[] ret = new Byte[signed.Length - 64]; |
|
194 Buffer.BlockCopy(signed, 32, ret, 0, ret.Length); |
|
195 return ret; |
|
196 } |
|
197 public int GetExtractedSize(int size) { |
|
198 if (size < 64) return -1; |
|
199 return size - 64; |
|
200 } |
|
201 } |
|
202 } |