Mercurial > hg > ucis.core
comparison NaCl/APIv2.cs @ 20:c873e3dd73fe
Added NaCl cryptography code
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 15 Apr 2013 00:43:48 +0200 |
parents | |
children | 29cf42a12c34 |
comparison
equal
deleted
inserted
replaced
19:b9ef273964fd | 20:c873e3dd73fe |
---|---|
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 } |