salsa20-jni.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /* _____ _
  2. * |_ _| |_ _ _ ___ ___ _ __ __ _
  3. * | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. * |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. *
  6. * Threema Java Client
  7. * Copyright (c) 2015-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. */
  21. #include <string.h>
  22. #include <jni.h>
  23. #define ROUNDS 20
  24. typedef unsigned int uint32;
  25. static const unsigned char sigma[16] = "expand 32-byte k";
  26. int crypto_stream_salsa20_ref(
  27. unsigned char *c,unsigned long long clen,
  28. const unsigned char *n,
  29. const unsigned char *k
  30. );
  31. int crypto_stream_salsa20_ref_xor(
  32. unsigned char *c,
  33. const unsigned char *m,unsigned long long mlen,
  34. const unsigned char *n,
  35. const unsigned char *k
  36. );
  37. int crypto_stream_salsa20_ref_xor_skip32(
  38. unsigned char *c0,
  39. unsigned char *c,unsigned long coffset,
  40. const unsigned char *m,unsigned long moffset,
  41. unsigned long long mlen,
  42. const unsigned char *n,
  43. const unsigned char *k
  44. );
  45. JNIEXPORT jint JNICALL Java_com_neilalexander_jnacl_crypto_salsa20_crypto_1stream_1native(JNIEnv* env, jclass cls,
  46. jbyteArray carr, jint clen, jbyteArray narr, jint noffset, jbyteArray karr)
  47. {
  48. jbyte *c;
  49. jbyte n[8];
  50. jbyte k[32];
  51. int res;
  52. if ((*env)->GetArrayLength(env, carr) < clen) {
  53. /* bad length */
  54. return 1;
  55. }
  56. (*env)->GetByteArrayRegion(env, narr, noffset, 8, n);
  57. (*env)->GetByteArrayRegion(env, karr, 0, 32, k);
  58. c = (*env)->GetPrimitiveArrayCritical(env, carr, NULL);
  59. if (c == NULL)
  60. return 4;
  61. res = crypto_stream_salsa20_ref((unsigned char *)c, clen, (unsigned char *)n, (unsigned char *)k);
  62. (*env)->ReleasePrimitiveArrayCritical(env, carr, c, 0);
  63. return res;
  64. }
  65. JNIEXPORT jint JNICALL Java_com_neilalexander_jnacl_crypto_salsa20_crypto_1stream_1xor_1native(JNIEnv* env, jclass cls,
  66. jbyteArray carr, jbyteArray marr, jint mlen, jbyteArray narr, jint noffset, jbyteArray karr)
  67. {
  68. jbyte *c, *m;
  69. jbyte n[8];
  70. jbyte k[32];
  71. int res;
  72. if ((*env)->GetArrayLength(env, marr) < mlen || (*env)->GetArrayLength(env, carr) < mlen) {
  73. /* bad length */
  74. return 1;
  75. }
  76. (*env)->GetByteArrayRegion(env, narr, noffset, 8, n);
  77. (*env)->GetByteArrayRegion(env, karr, 0, 32, k);
  78. c = (*env)->GetPrimitiveArrayCritical(env, carr, NULL);
  79. if (c == NULL)
  80. return 4;
  81. m = (*env)->GetPrimitiveArrayCritical(env, marr, NULL);
  82. if (m == NULL) {
  83. (*env)->ReleasePrimitiveArrayCritical(env, carr, c, 0);
  84. return 5;
  85. }
  86. res = crypto_stream_salsa20_ref_xor((unsigned char *)c, (unsigned char *)m, mlen, (unsigned char *)n, (unsigned char *)k);
  87. (*env)->ReleasePrimitiveArrayCritical(env, marr, m, 0);
  88. (*env)->ReleasePrimitiveArrayCritical(env, carr, c, 0);
  89. return res;
  90. }
  91. JNIEXPORT jint JNICALL Java_com_neilalexander_jnacl_crypto_salsa20_crypto_1stream_1xor_1skip32_1native(JNIEnv* env, jclass cls,
  92. jbyteArray c0arr, jbyteArray carr, jint coffset, jbyteArray marr, jint moffset, jint mlen, jbyteArray narr, jint noffset, jbyteArray karr)
  93. {
  94. jbyte c0[32];
  95. jbyte *c, *m;
  96. jbyte n[8];
  97. jbyte k[32];
  98. int res;
  99. if ((*env)->GetArrayLength(env, marr) < (moffset+mlen) || (*env)->GetArrayLength(env, carr) < (coffset+mlen)) {
  100. /* bad length */
  101. return 1;
  102. }
  103. (*env)->GetByteArrayRegion(env, narr, noffset, 8, n);
  104. (*env)->GetByteArrayRegion(env, karr, 0, 32, k);
  105. c = (*env)->GetPrimitiveArrayCritical(env, carr, NULL);
  106. if (c == NULL)
  107. return 4;
  108. m = (*env)->GetPrimitiveArrayCritical(env, marr, NULL);
  109. if (m == NULL) {
  110. (*env)->ReleasePrimitiveArrayCritical(env, carr, c, 0);
  111. return 5;
  112. }
  113. res = crypto_stream_salsa20_ref_xor_skip32((unsigned char *)c0, (unsigned char *)c, coffset, (unsigned char *)m, moffset, mlen, (unsigned char *)n, (unsigned char *)k);
  114. (*env)->ReleasePrimitiveArrayCritical(env, marr, m, 0);
  115. (*env)->ReleasePrimitiveArrayCritical(env, carr, c, 0);
  116. if (c0arr != NULL)
  117. (*env)->SetByteArrayRegion(env, c0arr, 0, 32, c0);
  118. return res;
  119. }
  120. /* Public Domain code copied verbatim from NaCl below */
  121. static uint32 rotate(uint32 u,int c)
  122. {
  123. return (u << c) | (u >> (32 - c));
  124. }
  125. static uint32 load_littleendian(const unsigned char *x)
  126. {
  127. return
  128. (uint32) (x[0]) \
  129. | (((uint32) (x[1])) << 8) \
  130. | (((uint32) (x[2])) << 16) \
  131. | (((uint32) (x[3])) << 24)
  132. ;
  133. }
  134. static void store_littleendian(unsigned char *x,uint32 u)
  135. {
  136. x[0] = u; u >>= 8;
  137. x[1] = u; u >>= 8;
  138. x[2] = u; u >>= 8;
  139. x[3] = u;
  140. }
  141. int crypto_core_salsa20_ref(
  142. unsigned char *out,
  143. const unsigned char *in,
  144. const unsigned char *k,
  145. const unsigned char *c
  146. )
  147. {
  148. uint32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
  149. uint32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
  150. int i;
  151. j0 = x0 = load_littleendian(c + 0);
  152. j1 = x1 = load_littleendian(k + 0);
  153. j2 = x2 = load_littleendian(k + 4);
  154. j3 = x3 = load_littleendian(k + 8);
  155. j4 = x4 = load_littleendian(k + 12);
  156. j5 = x5 = load_littleendian(c + 4);
  157. j6 = x6 = load_littleendian(in + 0);
  158. j7 = x7 = load_littleendian(in + 4);
  159. j8 = x8 = load_littleendian(in + 8);
  160. j9 = x9 = load_littleendian(in + 12);
  161. j10 = x10 = load_littleendian(c + 8);
  162. j11 = x11 = load_littleendian(k + 16);
  163. j12 = x12 = load_littleendian(k + 20);
  164. j13 = x13 = load_littleendian(k + 24);
  165. j14 = x14 = load_littleendian(k + 28);
  166. j15 = x15 = load_littleendian(c + 12);
  167. for (i = ROUNDS;i > 0;i -= 2) {
  168. x4 ^= rotate( x0+x12, 7);
  169. x8 ^= rotate( x4+ x0, 9);
  170. x12 ^= rotate( x8+ x4,13);
  171. x0 ^= rotate(x12+ x8,18);
  172. x9 ^= rotate( x5+ x1, 7);
  173. x13 ^= rotate( x9+ x5, 9);
  174. x1 ^= rotate(x13+ x9,13);
  175. x5 ^= rotate( x1+x13,18);
  176. x14 ^= rotate(x10+ x6, 7);
  177. x2 ^= rotate(x14+x10, 9);
  178. x6 ^= rotate( x2+x14,13);
  179. x10 ^= rotate( x6+ x2,18);
  180. x3 ^= rotate(x15+x11, 7);
  181. x7 ^= rotate( x3+x15, 9);
  182. x11 ^= rotate( x7+ x3,13);
  183. x15 ^= rotate(x11+ x7,18);
  184. x1 ^= rotate( x0+ x3, 7);
  185. x2 ^= rotate( x1+ x0, 9);
  186. x3 ^= rotate( x2+ x1,13);
  187. x0 ^= rotate( x3+ x2,18);
  188. x6 ^= rotate( x5+ x4, 7);
  189. x7 ^= rotate( x6+ x5, 9);
  190. x4 ^= rotate( x7+ x6,13);
  191. x5 ^= rotate( x4+ x7,18);
  192. x11 ^= rotate(x10+ x9, 7);
  193. x8 ^= rotate(x11+x10, 9);
  194. x9 ^= rotate( x8+x11,13);
  195. x10 ^= rotate( x9+ x8,18);
  196. x12 ^= rotate(x15+x14, 7);
  197. x13 ^= rotate(x12+x15, 9);
  198. x14 ^= rotate(x13+x12,13);
  199. x15 ^= rotate(x14+x13,18);
  200. }
  201. x0 += j0;
  202. x1 += j1;
  203. x2 += j2;
  204. x3 += j3;
  205. x4 += j4;
  206. x5 += j5;
  207. x6 += j6;
  208. x7 += j7;
  209. x8 += j8;
  210. x9 += j9;
  211. x10 += j10;
  212. x11 += j11;
  213. x12 += j12;
  214. x13 += j13;
  215. x14 += j14;
  216. x15 += j15;
  217. store_littleendian(out + 0,x0);
  218. store_littleendian(out + 4,x1);
  219. store_littleendian(out + 8,x2);
  220. store_littleendian(out + 12,x3);
  221. store_littleendian(out + 16,x4);
  222. store_littleendian(out + 20,x5);
  223. store_littleendian(out + 24,x6);
  224. store_littleendian(out + 28,x7);
  225. store_littleendian(out + 32,x8);
  226. store_littleendian(out + 36,x9);
  227. store_littleendian(out + 40,x10);
  228. store_littleendian(out + 44,x11);
  229. store_littleendian(out + 48,x12);
  230. store_littleendian(out + 52,x13);
  231. store_littleendian(out + 56,x14);
  232. store_littleendian(out + 60,x15);
  233. return 0;
  234. }
  235. int crypto_core_hsalsa20_ref(
  236. unsigned char *out,
  237. const unsigned char *in,
  238. const unsigned char *k,
  239. const unsigned char *c
  240. )
  241. {
  242. uint32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
  243. uint32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
  244. int i;
  245. j0 = x0 = load_littleendian(c + 0);
  246. j1 = x1 = load_littleendian(k + 0);
  247. j2 = x2 = load_littleendian(k + 4);
  248. j3 = x3 = load_littleendian(k + 8);
  249. j4 = x4 = load_littleendian(k + 12);
  250. j5 = x5 = load_littleendian(c + 4);
  251. j6 = x6 = load_littleendian(in + 0);
  252. j7 = x7 = load_littleendian(in + 4);
  253. j8 = x8 = load_littleendian(in + 8);
  254. j9 = x9 = load_littleendian(in + 12);
  255. j10 = x10 = load_littleendian(c + 8);
  256. j11 = x11 = load_littleendian(k + 16);
  257. j12 = x12 = load_littleendian(k + 20);
  258. j13 = x13 = load_littleendian(k + 24);
  259. j14 = x14 = load_littleendian(k + 28);
  260. j15 = x15 = load_littleendian(c + 12);
  261. for (i = ROUNDS;i > 0;i -= 2) {
  262. x4 ^= rotate( x0+x12, 7);
  263. x8 ^= rotate( x4+ x0, 9);
  264. x12 ^= rotate( x8+ x4,13);
  265. x0 ^= rotate(x12+ x8,18);
  266. x9 ^= rotate( x5+ x1, 7);
  267. x13 ^= rotate( x9+ x5, 9);
  268. x1 ^= rotate(x13+ x9,13);
  269. x5 ^= rotate( x1+x13,18);
  270. x14 ^= rotate(x10+ x6, 7);
  271. x2 ^= rotate(x14+x10, 9);
  272. x6 ^= rotate( x2+x14,13);
  273. x10 ^= rotate( x6+ x2,18);
  274. x3 ^= rotate(x15+x11, 7);
  275. x7 ^= rotate( x3+x15, 9);
  276. x11 ^= rotate( x7+ x3,13);
  277. x15 ^= rotate(x11+ x7,18);
  278. x1 ^= rotate( x0+ x3, 7);
  279. x2 ^= rotate( x1+ x0, 9);
  280. x3 ^= rotate( x2+ x1,13);
  281. x0 ^= rotate( x3+ x2,18);
  282. x6 ^= rotate( x5+ x4, 7);
  283. x7 ^= rotate( x6+ x5, 9);
  284. x4 ^= rotate( x7+ x6,13);
  285. x5 ^= rotate( x4+ x7,18);
  286. x11 ^= rotate(x10+ x9, 7);
  287. x8 ^= rotate(x11+x10, 9);
  288. x9 ^= rotate( x8+x11,13);
  289. x10 ^= rotate( x9+ x8,18);
  290. x12 ^= rotate(x15+x14, 7);
  291. x13 ^= rotate(x12+x15, 9);
  292. x14 ^= rotate(x13+x12,13);
  293. x15 ^= rotate(x14+x13,18);
  294. }
  295. x0 += j0;
  296. x1 += j1;
  297. x2 += j2;
  298. x3 += j3;
  299. x4 += j4;
  300. x5 += j5;
  301. x6 += j6;
  302. x7 += j7;
  303. x8 += j8;
  304. x9 += j9;
  305. x10 += j10;
  306. x11 += j11;
  307. x12 += j12;
  308. x13 += j13;
  309. x14 += j14;
  310. x15 += j15;
  311. x0 -= load_littleendian(c + 0);
  312. x5 -= load_littleendian(c + 4);
  313. x10 -= load_littleendian(c + 8);
  314. x15 -= load_littleendian(c + 12);
  315. x6 -= load_littleendian(in + 0);
  316. x7 -= load_littleendian(in + 4);
  317. x8 -= load_littleendian(in + 8);
  318. x9 -= load_littleendian(in + 12);
  319. store_littleendian(out + 0,x0);
  320. store_littleendian(out + 4,x5);
  321. store_littleendian(out + 8,x10);
  322. store_littleendian(out + 12,x15);
  323. store_littleendian(out + 16,x6);
  324. store_littleendian(out + 20,x7);
  325. store_littleendian(out + 24,x8);
  326. store_littleendian(out + 28,x9);
  327. return 0;
  328. }
  329. int crypto_stream_salsa20_ref_xor(
  330. unsigned char *c,
  331. const unsigned char *m,unsigned long long mlen,
  332. const unsigned char *n,
  333. const unsigned char *k
  334. )
  335. {
  336. unsigned char in[16];
  337. unsigned char block[64];
  338. int i;
  339. unsigned int u;
  340. if (!mlen) return 0;
  341. for (i = 0;i < 8;++i) in[i] = n[i];
  342. for (i = 8;i < 16;++i) in[i] = 0;
  343. while (mlen >= 64) {
  344. crypto_core_salsa20_ref(block,in,k,sigma);
  345. for (i = 0;i < 64;++i) c[i] = m[i] ^ block[i];
  346. u = 1;
  347. for (i = 8;i < 16;++i) {
  348. u += (unsigned int) in[i];
  349. in[i] = u;
  350. u >>= 8;
  351. }
  352. mlen -= 64;
  353. c += 64;
  354. m += 64;
  355. }
  356. if (mlen) {
  357. crypto_core_salsa20_ref(block,in,k,sigma);
  358. for (i = 0;i < mlen;++i) c[i] = m[i] ^ block[i];
  359. }
  360. return 0;
  361. }
  362. int crypto_stream_salsa20_ref_xor_skip32(
  363. unsigned char *c0,
  364. unsigned char *c,unsigned long coffset,
  365. const unsigned char *m,unsigned long moffset,
  366. unsigned long long mlen,
  367. const unsigned char *n,
  368. const unsigned char *k
  369. )
  370. {
  371. unsigned char in[16];
  372. unsigned char blk1[64];
  373. unsigned char blk2[64];
  374. unsigned char *prevblock;
  375. unsigned char *curblock;
  376. unsigned char *tmpblock;
  377. int i;
  378. unsigned int u;
  379. if (!mlen) return 0;
  380. for (i = 0;i < 8;++i) in[i] = n[i];
  381. for (i = 8;i < 16;++i) in[i] = 0;
  382. prevblock = blk1;
  383. curblock = blk2;
  384. crypto_core_salsa20_ref(prevblock,in,k,sigma);
  385. if (c0 != NULL) {
  386. for (i = 0; i < 32; i++) c0[i] = prevblock[i];
  387. }
  388. while (mlen >= 64) {
  389. u = 1;
  390. for (i = 8;i < 16;++i) {
  391. u += (unsigned int) in[i];
  392. in[i] = u;
  393. u >>= 8;
  394. }
  395. crypto_core_salsa20_ref(curblock,in,k,sigma);
  396. for (i = 0;i < 32;++i) c[i+coffset] = m[i+moffset] ^ prevblock[i+32];
  397. for (i = 32;i < 64;++i) c[i+coffset] = m[i+moffset] ^ curblock[i-32];
  398. mlen -= 64;
  399. c += 64;
  400. m += 64;
  401. tmpblock = prevblock;
  402. prevblock = curblock;
  403. curblock = tmpblock;
  404. }
  405. if (mlen) {
  406. u = 1;
  407. for (i = 8;i < 16;++i) {
  408. u += (unsigned int) in[i];
  409. in[i] = u;
  410. u >>= 8;
  411. }
  412. crypto_core_salsa20_ref(curblock,in,k,sigma);
  413. for (i = 0;i < mlen && i < 32;++i) c[i+coffset] = m[i+moffset] ^ prevblock[i+32];
  414. for (i = 32;i < mlen && i < 64;++i) c[i+coffset] = m[i+moffset] ^ curblock[i-32];
  415. }
  416. return 0;
  417. }
  418. int crypto_stream_salsa20_ref(
  419. unsigned char *c,unsigned long long clen,
  420. const unsigned char *n,
  421. const unsigned char *k
  422. )
  423. {
  424. unsigned char in[16];
  425. unsigned char block[64];
  426. int i;
  427. unsigned int u;
  428. if (!clen) return 0;
  429. for (i = 0;i < 8;++i) in[i] = n[i];
  430. for (i = 8;i < 16;++i) in[i] = 0;
  431. while (clen >= 64) {
  432. crypto_core_salsa20_ref(c,in,k,sigma);
  433. u = 1;
  434. for (i = 8;i < 16;++i) {
  435. u += (unsigned int) in[i];
  436. in[i] = u;
  437. u >>= 8;
  438. }
  439. clen -= 64;
  440. c += 64;
  441. }
  442. if (clen) {
  443. crypto_core_salsa20_ref(block,in,k,sigma);
  444. for (i = 0;i < clen;++i) c[i] = block[i];
  445. }
  446. return 0;
  447. }