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 }