NaClCrypto.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2012-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "NaClCrypto.h"
  21. #import "crypto_box.h"
  22. #import "crypto_scalarmult_curve25519.h"
  23. #import "crypto_secretbox.h"
  24. #import "crypto_stream.h"
  25. #import "devurandom.h"
  26. #ifdef DEBUG
  27. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  28. #else
  29. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  30. #endif
  31. @implementation NaClCrypto
  32. #if (kNaClCryptoPubKeySize != crypto_box_PUBLICKEYBYTES)
  33. #error Bad public key size
  34. #endif
  35. #if (kNaClCryptoSecKeySize != crypto_box_SECRETKEYBYTES)
  36. #error Bad secret key size
  37. #endif
  38. #if (kNaClCryptoNonceSize != crypto_box_NONCEBYTES)
  39. #error Bad nonce size
  40. #endif
  41. #if (kNaClBoxOverhead != (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES))
  42. #error Bad box overhead size
  43. #endif
  44. #if (kNaClCryptoSymmKeySize != crypto_secretbox_KEYBYTES)
  45. #error Bad symmetric key size
  46. #endif
  47. #if (kNaClCryptoSymmNonceSize != crypto_secretbox_NONCEBYTES)
  48. #error Bad symmetric nonce size
  49. #endif
  50. #if (kNaClCryptoStreamKeySize != crypto_stream_KEYBYTES)
  51. #error Bad stream key size
  52. #endif
  53. #if (kNaClCryptoStreamNonceSize != crypto_stream_NONCEBYTES)
  54. #error Bad stream nonce size
  55. #endif
  56. + (NaClCrypto*)sharedCrypto {
  57. static NaClCrypto *instance;
  58. @synchronized (self) {
  59. if (!instance)
  60. instance = [[NaClCrypto alloc] init];
  61. }
  62. return instance;
  63. }
  64. - (id)init
  65. {
  66. self = [super init];
  67. if (self) {
  68. [self selfTest];
  69. }
  70. return self;
  71. }
  72. - (void)generateKeyPairPublicKey:(NSData**)publicKey secretKey:(NSData**)secretKey withSeed:(NSData*)seed {
  73. if (seed.length != kNaClCryptoSecKeySize)
  74. @throw([NSException exceptionWithName:@"BadSeedSizeException" reason:@"Invalid seed size" userInfo:nil]);
  75. unsigned char *pk = malloc(kNaClCryptoPubKeySize);
  76. if (pk == NULL)
  77. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  78. unsigned char *sk = malloc(kNaClCryptoSecKeySize);
  79. if (sk == NULL) {
  80. free(pk);
  81. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  82. }
  83. /* mix seed with random data */
  84. randombytes(sk, kNaClCryptoSecKeySize);
  85. for (int i = 0; i < kNaClCryptoSecKeySize; i++)
  86. sk[i] ^= ((unsigned char*)seed.bytes)[i];
  87. /* sidestepping crypto_box_keypair to provide our own secret key */
  88. if (crypto_scalarmult_curve25519_base(pk, sk) != 0) {
  89. /* shouldn't happen */
  90. free(pk);
  91. free(sk);
  92. @throw([NSException exceptionWithName:@"CryptoException" reason:@"Crypto error" userInfo:nil]);
  93. }
  94. *publicKey = [NSData dataWithBytesNoCopy:pk length:kNaClCryptoPubKeySize];
  95. *secretKey = [NSData dataWithBytesNoCopy:sk length:kNaClCryptoSecKeySize];
  96. }
  97. - (void)generateKeyPairPublicKey:(NSData**)publicKey secretKey:(NSData**)secretKey {
  98. unsigned char *pk = malloc(kNaClCryptoPubKeySize);
  99. if (pk == NULL)
  100. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  101. unsigned char *sk = malloc(kNaClCryptoSecKeySize);
  102. if (sk == NULL) {
  103. free(pk);
  104. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  105. }
  106. if (crypto_box_keypair(pk, sk) != 0) {
  107. /* shouldn't happen */
  108. free(pk);
  109. free(sk);
  110. @throw([NSException exceptionWithName:@"CryptoException" reason:@"Crypto error" userInfo:nil]);
  111. }
  112. *publicKey = [NSData dataWithBytesNoCopy:pk length:kNaClCryptoPubKeySize];
  113. *secretKey = [NSData dataWithBytesNoCopy:sk length:kNaClCryptoSecKeySize];
  114. }
  115. - (NSData*)derivePublicKeyFromSecretKey:(NSData*)secretKey {
  116. if (secretKey.length != kNaClCryptoSecKeySize)
  117. @throw([NSException exceptionWithName:@"BadSecKeySizeException" reason:@"Invalid secret key size" userInfo:nil]);
  118. unsigned char *pk = malloc(kNaClCryptoPubKeySize);
  119. if (pk == NULL)
  120. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  121. /* sidestepping crypto_box_keypair to provide our own secret key */
  122. if (crypto_scalarmult_curve25519_base(pk, secretKey.bytes) != 0) {
  123. /* shouldn't happen */
  124. free(pk);
  125. @throw([NSException exceptionWithName:@"CryptoException" reason:@"Crypto error" userInfo:nil]);
  126. }
  127. return [NSData dataWithBytesNoCopy:pk length:kNaClCryptoPubKeySize];
  128. }
  129. - (NSData*)encryptData:(NSData*)plaintext withPublicKey:(NSData*)publicKey signKey:(NSData*)signKey nonce:(NSData*)nonce {
  130. /* input sanity checks */
  131. if (publicKey.length != kNaClCryptoPubKeySize)
  132. @throw([NSException exceptionWithName:@"BadPubKeySizeException" reason:@"Invalid public key size" userInfo:nil]);
  133. if (signKey.length != kNaClCryptoSecKeySize)
  134. @throw([NSException exceptionWithName:@"BadSecKeySizeException" reason:@"Invalid secret key size" userInfo:nil]);
  135. if (nonce.length != kNaClCryptoNonceSize)
  136. @throw([NSException exceptionWithName:@"BadNonceSizeException" reason:@"Invalid nonce size" userInfo:nil]);
  137. if (plaintext.length == 0)
  138. @throw([NSException exceptionWithName:@"EmptyMessageException" reason:@"Empty message" userInfo:nil]);
  139. /* must copy plaintext since we need to zero-pad it */
  140. NSUInteger mlen = plaintext.length + crypto_box_ZEROBYTES;
  141. char *ctbuf = malloc(mlen);
  142. if (ctbuf == NULL) {
  143. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  144. }
  145. bzero(ctbuf, crypto_box_ZEROBYTES);
  146. memcpy(&ctbuf[crypto_box_ZEROBYTES], plaintext.bytes, plaintext.length);
  147. if (crypto_box((unsigned char *)ctbuf, (unsigned char *)ctbuf, mlen, nonce.bytes,
  148. publicKey.bytes, signKey.bytes) != 0) {
  149. /* shouldn't happen */
  150. free(ctbuf);
  151. @throw([NSException exceptionWithName:@"CryptoException" reason:@"Crypto error" userInfo:nil]);
  152. }
  153. NSData *ciphertext = [NSData dataWithBytes:&ctbuf[crypto_box_BOXZEROBYTES] length:(mlen - crypto_box_BOXZEROBYTES)];
  154. free(ctbuf);
  155. return ciphertext;
  156. }
  157. - (NSData*)decryptData:(NSData*)ciphertext withSecretKey:(NSData*)secretKey signKey:(NSData*)signKey nonce:(NSData*)nonce {
  158. /* input sanity checks */
  159. if (secretKey.length != kNaClCryptoSecKeySize)
  160. @throw([NSException exceptionWithName:@"BadSecKeySizeException" reason:@"Invalid secret key size" userInfo:nil]);
  161. if (signKey.length != kNaClCryptoPubKeySize)
  162. @throw([NSException exceptionWithName:@"BadPubKeySizeException" reason:@"Invalid public key size" userInfo:nil]);
  163. if (nonce.length != kNaClCryptoNonceSize)
  164. @throw([NSException exceptionWithName:@"BadNonceSizeException" reason:@"Invalid nonce size" userInfo:nil]);
  165. if (ciphertext.length <= crypto_box_BOXZEROBYTES)
  166. @throw([NSException exceptionWithName:@"TruncatedMessageException" reason:@"Truncated message" userInfo:nil]);
  167. /* must copy ciphertext since we need to zero-pad it */
  168. NSUInteger clen = ciphertext.length + crypto_box_BOXZEROBYTES;
  169. char *msgbuf = malloc(clen);
  170. if (msgbuf == NULL)
  171. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  172. bzero(msgbuf, crypto_box_BOXZEROBYTES);
  173. memcpy(&msgbuf[crypto_box_BOXZEROBYTES], ciphertext.bytes, ciphertext.length);
  174. if (crypto_box_open((unsigned char *)msgbuf, (unsigned char *)msgbuf, clen, nonce.bytes,
  175. signKey.bytes, secretKey.bytes) != 0) {
  176. /* probably bad signature */
  177. free(msgbuf);
  178. return nil;
  179. }
  180. NSData *plaintext = [NSData dataWithBytes:&msgbuf[crypto_box_ZEROBYTES] length:(clen - crypto_box_ZEROBYTES)];
  181. free(msgbuf);
  182. return plaintext;
  183. }
  184. - (NSData*)streamXorData:(NSData*)data secretKey:(NSData*)secretKey nonce:(NSData*)nonce {
  185. if (secretKey.length != kNaClCryptoStreamKeySize)
  186. @throw([NSException exceptionWithName:@"BadStreamKeySizeException" reason:@"Invalid stream key size" userInfo:nil]);
  187. if (nonce.length != kNaClCryptoStreamNonceSize)
  188. @throw([NSException exceptionWithName:@"BadStreamNonceSizeException" reason:@"Invalid stream nonce size" userInfo:nil]);
  189. void *outData = malloc(data.length);
  190. if (outData == nil)
  191. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  192. if (crypto_stream_xor(outData, data.bytes, data.length, nonce.bytes, secretKey.bytes) != 0) {
  193. free(outData);
  194. @throw([NSException exceptionWithName:@"CryptoException" reason:@"Crypto error" userInfo:nil]);
  195. }
  196. return [NSData dataWithBytesNoCopy:outData length:data.length];
  197. }
  198. - (NSData*)symmetricEncryptData:(NSData*)plaintext withKey:(NSData*)key nonce:(NSData*)nonce {
  199. if (key.length != kNaClCryptoSymmKeySize)
  200. @throw([NSException exceptionWithName:@"BadSymmetricKeySizeException" reason:@"Invalid symmetric key size" userInfo:nil]);
  201. if (nonce.length != kNaClCryptoSymmNonceSize)
  202. @throw([NSException exceptionWithName:@"BadSymmetricNonceSizeException" reason:@"Invalid symmetric nonce size" userInfo:nil]);
  203. NSUInteger mlen = plaintext.length + crypto_secretbox_ZEROBYTES;
  204. char *ctbuf = malloc(mlen);
  205. if (ctbuf == NULL) {
  206. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  207. }
  208. bzero(ctbuf, crypto_secretbox_ZEROBYTES);
  209. memcpy(&ctbuf[crypto_secretbox_ZEROBYTES], plaintext.bytes, plaintext.length);
  210. if (crypto_secretbox((unsigned char *)ctbuf, (unsigned char *)ctbuf, mlen, nonce.bytes, key.bytes) != 0) {
  211. /* shouldn't happen */
  212. free(ctbuf);
  213. @throw([NSException exceptionWithName:@"CryptoException" reason:@"Crypto error" userInfo:nil]);
  214. }
  215. NSData *ciphertext = [NSData dataWithBytes:&ctbuf[crypto_secretbox_BOXZEROBYTES] length:(mlen - crypto_secretbox_BOXZEROBYTES)];
  216. free(ctbuf);
  217. return ciphertext;
  218. }
  219. - (NSData*)symmetricDecryptData:(NSData*)ciphertext withKey:(NSData*)key nonce:(NSData*)nonce {
  220. if (key.length != kNaClCryptoSymmKeySize)
  221. @throw([NSException exceptionWithName:@"BadSymmetricKeySizeException" reason:@"Invalid symmetric key size" userInfo:nil]);
  222. if (nonce.length != kNaClCryptoSymmNonceSize)
  223. @throw([NSException exceptionWithName:@"BadSymmetricNonceSizeException" reason:@"Invalid symmetric nonce size" userInfo:nil]);
  224. NSUInteger clen = ciphertext.length + crypto_secretbox_BOXZEROBYTES;
  225. char *msgbuf = malloc(clen);
  226. if (msgbuf == NULL)
  227. @throw([NSException exceptionWithName:@"MemoryAllocationException" reason:@"Cannot allocate memory" userInfo:nil]);
  228. bzero(msgbuf, crypto_secretbox_BOXZEROBYTES);
  229. memcpy(&msgbuf[crypto_secretbox_BOXZEROBYTES], ciphertext.bytes, ciphertext.length);
  230. if (crypto_secretbox_open((unsigned char *)msgbuf, (unsigned char *)msgbuf, clen, nonce.bytes, key.bytes) != 0) {
  231. /* probably bad signature */
  232. free(msgbuf);
  233. return nil;
  234. }
  235. NSData *plaintext = [NSData dataWithBytes:&msgbuf[crypto_secretbox_ZEROBYTES] length:(clen - crypto_secretbox_ZEROBYTES)];
  236. free(msgbuf);
  237. return plaintext;
  238. }
  239. - (void)selfTest {
  240. /* test vectors from tests/box.* in nacl distribution */
  241. unsigned char _alicepk[] = {
  242. 0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
  243. ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
  244. ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
  245. ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a
  246. };
  247. NSData *alicepk = [NSData dataWithBytes:_alicepk length:sizeof(_alicepk)];
  248. unsigned char _alicesk[] = {
  249. 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
  250. ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
  251. ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
  252. ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a
  253. };
  254. NSData *alicesk = [NSData dataWithBytes:_alicesk length:sizeof(_alicesk)];
  255. unsigned char _bobpk[] = {
  256. 0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
  257. ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
  258. ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
  259. ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f
  260. };
  261. NSData *bobpk = [NSData dataWithBytes:_bobpk length:sizeof(_bobpk)];
  262. unsigned char _bobsk[] = {
  263. 0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
  264. ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
  265. ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
  266. ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb
  267. };
  268. NSData *bobsk = [NSData dataWithBytes:_bobsk length:sizeof(_bobsk)];
  269. unsigned char _nonce[] = {
  270. 0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
  271. ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
  272. ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37
  273. };
  274. NSData *nonce = [NSData dataWithBytes:_nonce length:sizeof(_nonce)];
  275. unsigned char _m[] = {
  276. 0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
  277. ,0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
  278. ,0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
  279. ,0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
  280. ,0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
  281. ,0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
  282. ,0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
  283. ,0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
  284. ,0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
  285. ,0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
  286. ,0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
  287. ,0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
  288. ,0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
  289. ,0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
  290. ,0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
  291. ,0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
  292. ,0x5e,0x07,0x05
  293. };
  294. NSData *m = [NSData dataWithBytes:_m length:sizeof(_m)];
  295. unsigned char _c_expected[] = {
  296. 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5
  297. ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9
  298. ,0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
  299. ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
  300. ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
  301. ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
  302. ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
  303. ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
  304. ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
  305. ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
  306. ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
  307. ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
  308. ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
  309. ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
  310. ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
  311. ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
  312. ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
  313. ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
  314. ,0xe3,0x55,0xa5
  315. };
  316. NSData *c_expected = [NSData dataWithBytes:_c_expected length:sizeof(_c_expected)];
  317. /* encrypt data and compare with expected result */
  318. NSData *c = [self encryptData:m withPublicKey:bobpk signKey:alicesk nonce:nonce];
  319. if (![c_expected isEqualToData:c]) {
  320. @throw([NSException exceptionWithName:@"CryptoSelfTestFailedException" reason:@"Crypto self-test failed" userInfo:nil]);
  321. }
  322. /* decrypt data and compare with plaintext */
  323. NSData *p_d = [self decryptData:c withSecretKey:bobsk signKey:alicepk nonce:nonce];
  324. if (![p_d isEqualToData:m]) {
  325. @throw([NSException exceptionWithName:@"CryptoSelfTestFailedException" reason:@"Crypto self-test failed" userInfo:nil]);
  326. }
  327. DDLogInfo(@"Crypto self-test passed");
  328. }
  329. - (void)longTest {
  330. int i;
  331. for (i = 0; i < 1000; i++) {
  332. int msglen = i + 1;
  333. NSData *pk1, *sk1, *pk2, *sk2;
  334. [self generateKeyPairPublicKey:&pk1 secretKey:&sk1];
  335. [self generateKeyPairPublicKey:&pk2 secretKey:&sk2];
  336. NSData *msg = [self randomBytes:msglen];
  337. NSData *nonce = [self randomBytes:kNaClCryptoNonceSize];
  338. NSData *c = [self encryptData:msg withPublicKey:pk2 signKey:sk1 nonce:nonce];
  339. NSData *newmsg = [self decryptData:c withSecretKey:sk2 signKey:pk1 nonce:nonce];
  340. if (![newmsg isEqualToData:msg]) {
  341. @throw([NSException exceptionWithName:@"CryptoSelfTestFailedException" reason:@"Crypto self-test failed" userInfo:nil]);
  342. }
  343. }
  344. }
  345. - (NSData*)randomBytes:(int)len {
  346. unsigned char *random = malloc(len);
  347. if (random == NULL) {
  348. @throw([NSException exceptionWithName:@"AllocMemoryForRandomBytesFailed" reason:@"Cannot allocate memory for random bytes" userInfo:nil]);
  349. }
  350. randombytes(random, len);
  351. return [NSData dataWithBytesNoCopy:random length:len];
  352. }
  353. - (NSData*)zeroBytes:(int)len {
  354. unsigned char *zero = malloc(len);
  355. if (zero == NULL) {
  356. @throw([NSException exceptionWithName:@"AllocMemoryForZeroBytesFailed" reason:@"Cannot allocate memory for zero bytes" userInfo:nil]);
  357. }
  358. bzero(zero, len);
  359. return [NSData dataWithBytesNoCopy:zero length:len];
  360. }
  361. - (double)benchmark {
  362. /* run 1000 encryption operations on a 1024 byte message
  363. and return the number of encryption operations per second */
  364. DDLogInfo(@"Generating key...");
  365. int i;
  366. NSData *pk, *sk;
  367. [self generateKeyPairPublicKey:&pk secretKey:&sk];
  368. DDLogInfo(@"Preparing message...");
  369. unsigned char _msg[1024];
  370. for (i = 0; i < 1024; i++)
  371. _msg[i] = (i % 256);
  372. NSData *msg = [NSData dataWithBytes:_msg length:1024];
  373. unsigned char _nonce[kNaClCryptoNonceSize];
  374. for (i = 0; i < kNaClCryptoNonceSize; i++)
  375. _nonce[i] = (i % 256);
  376. NSData *nonce = [NSData dataWithBytes:_nonce length:kNaClCryptoNonceSize];
  377. DDLogInfo(@"Benchmarking...");
  378. NSDate *start = [NSDate date];
  379. for (i = 0; i < 1000; i++) {
  380. [self encryptData:msg withPublicKey:pk signKey:sk nonce:nonce];
  381. }
  382. DDLogInfo(@"Benchmark done.");
  383. return (1000 / ([start timeIntervalSinceNow] * -1.0));
  384. }
  385. @end