/security/nss/lib/freebl/aeskeywrap.c

http://github.com/zpao/v8monkey · C · 417 lines · 274 code · 24 blank · 119 comment · 70 complexity · 6fcaf84bc1b743ed1193d9c43418942f MD5 · raw file

  1. /*
  2. * aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is the Netscape security libraries.
  18. *
  19. * The Initial Developer of the Original Code is
  20. * Netscape Communications Corporation.
  21. * Portions created by the Initial Developer are Copyright (C) 2002
  22. * the Initial Developer. All Rights Reserved.
  23. *
  24. * Contributor(s):
  25. *
  26. * Alternatively, the contents of this file may be used under the terms of
  27. * either the GNU General Public License Version 2 or later (the "GPL"), or
  28. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29. * in which case the provisions of the GPL or the LGPL are applicable instead
  30. * of those above. If you wish to allow use of your version of this file only
  31. * under the terms of either the GPL or the LGPL, and not to allow others to
  32. * use your version of this file under the terms of the MPL, indicate your
  33. * decision by deleting the provisions above and replace them with the notice
  34. * and other provisions required by the GPL or the LGPL. If you do not delete
  35. * the provisions above, a recipient may use your version of this file under
  36. * the terms of any one of the MPL, the GPL or the LGPL.
  37. *
  38. * ***** END LICENSE BLOCK ***** */
  39. /* $Id: aeskeywrap.c,v 1.5 2008/11/18 19:48:21 rrelyea%redhat.com Exp $ */
  40. /* $Id: aeskeywrap.c,v 1.5 2008/11/18 19:48:21 rrelyea%redhat.com Exp $ */
  41. #ifdef FREEBL_NO_DEPEND
  42. #include "stubs.h"
  43. #endif
  44. #include "prcpucfg.h"
  45. #if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG)
  46. #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0
  47. #else
  48. #define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1
  49. #endif
  50. #include "prtypes.h" /* for PRUintXX */
  51. #include "secport.h" /* for PORT_XXX */
  52. #include "secerr.h"
  53. #include "blapi.h" /* for AES_ functions */
  54. #include "rijndael.h"
  55. struct AESKeyWrapContextStr {
  56. unsigned char iv[AES_KEY_WRAP_IV_BYTES];
  57. AESContext aescx;
  58. };
  59. /******************************************/
  60. /*
  61. ** AES key wrap algorithm, RFC 3394
  62. */
  63. AESKeyWrapContext *
  64. AESKeyWrap_AllocateContext(void)
  65. {
  66. AESKeyWrapContext * cx = PORT_New(AESKeyWrapContext);
  67. return cx;
  68. }
  69. SECStatus
  70. AESKeyWrap_InitContext(AESKeyWrapContext *cx,
  71. const unsigned char *key,
  72. unsigned int keylen,
  73. const unsigned char *iv,
  74. int x1,
  75. unsigned int encrypt,
  76. unsigned int x2)
  77. {
  78. SECStatus rv = SECFailure;
  79. if (!cx) {
  80. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  81. return SECFailure;
  82. }
  83. if (iv) {
  84. memcpy(cx->iv, iv, sizeof cx->iv);
  85. } else {
  86. memset(cx->iv, 0xA6, sizeof cx->iv);
  87. }
  88. rv = AES_InitContext(&cx->aescx, key, keylen, NULL, NSS_AES, encrypt,
  89. AES_BLOCK_SIZE);
  90. return rv;
  91. }
  92. /*
  93. ** Create a new AES context suitable for AES encryption/decryption.
  94. ** "key" raw key data
  95. ** "keylen" the number of bytes of key data (16, 24, or 32)
  96. */
  97. extern AESKeyWrapContext *
  98. AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv,
  99. int encrypt, unsigned int keylen)
  100. {
  101. SECStatus rv;
  102. AESKeyWrapContext * cx = AESKeyWrap_AllocateContext();
  103. if (!cx)
  104. return NULL; /* error is already set */
  105. rv = AESKeyWrap_InitContext(cx, key, keylen, iv, 0, encrypt, 0);
  106. if (rv != SECSuccess) {
  107. PORT_Free(cx);
  108. cx = NULL; /* error should already be set */
  109. }
  110. return cx;
  111. }
  112. /*
  113. ** Destroy a AES KeyWrap context.
  114. ** "cx" the context
  115. ** "freeit" if PR_TRUE then free the object as well as its sub-objects
  116. */
  117. extern void
  118. AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
  119. {
  120. if (cx) {
  121. AES_DestroyContext(&cx->aescx, PR_FALSE);
  122. /* memset(cx, 0, sizeof *cx); */
  123. if (freeit)
  124. PORT_Free(cx);
  125. }
  126. }
  127. #if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
  128. /* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian
  129. ** (Most significant byte first) in memory. The only ALU operations done
  130. ** on them are increment, decrement, and XOR. So, on little-endian CPUs,
  131. ** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations
  132. ** are simulated in the following code. This is thought to be faster and
  133. ** simpler than trying to convert the data to little-endian and back.
  134. */
  135. /* A and T point to two 64-bit values stored most signficant byte first
  136. ** (big endian). This function increments the 64-bit value T, and then
  137. ** XORs it with A, changing A.
  138. */
  139. static void
  140. increment_and_xor(unsigned char *A, unsigned char *T)
  141. {
  142. if (!++T[7])
  143. if (!++T[6])
  144. if (!++T[5])
  145. if (!++T[4])
  146. if (!++T[3])
  147. if (!++T[2])
  148. if (!++T[1])
  149. ++T[0];
  150. A[0] ^= T[0];
  151. A[1] ^= T[1];
  152. A[2] ^= T[2];
  153. A[3] ^= T[3];
  154. A[4] ^= T[4];
  155. A[5] ^= T[5];
  156. A[6] ^= T[6];
  157. A[7] ^= T[7];
  158. }
  159. /* A and T point to two 64-bit values stored most signficant byte first
  160. ** (big endian). This function XORs T with A, giving a new A, then
  161. ** decrements the 64-bit value T.
  162. */
  163. static void
  164. xor_and_decrement(unsigned char *A, unsigned char *T)
  165. {
  166. A[0] ^= T[0];
  167. A[1] ^= T[1];
  168. A[2] ^= T[2];
  169. A[3] ^= T[3];
  170. A[4] ^= T[4];
  171. A[5] ^= T[5];
  172. A[6] ^= T[6];
  173. A[7] ^= T[7];
  174. if (!T[7]--)
  175. if (!T[6]--)
  176. if (!T[5]--)
  177. if (!T[4]--)
  178. if (!T[3]--)
  179. if (!T[2]--)
  180. if (!T[1]--)
  181. T[0]--;
  182. }
  183. /* Given an unsigned long t (in host byte order), store this value as a
  184. ** 64-bit big-endian value (MSB first) in *pt.
  185. */
  186. static void
  187. set_t(unsigned char *pt, unsigned long t)
  188. {
  189. pt[7] = (unsigned char)t; t >>= 8;
  190. pt[6] = (unsigned char)t; t >>= 8;
  191. pt[5] = (unsigned char)t; t >>= 8;
  192. pt[4] = (unsigned char)t; t >>= 8;
  193. pt[3] = (unsigned char)t; t >>= 8;
  194. pt[2] = (unsigned char)t; t >>= 8;
  195. pt[1] = (unsigned char)t; t >>= 8;
  196. pt[0] = (unsigned char)t;
  197. }
  198. #endif
  199. /*
  200. ** Perform AES key wrap.
  201. ** "cx" the context
  202. ** "output" the output buffer to store the encrypted data.
  203. ** "outputLen" how much data is stored in "output". Set by the routine
  204. ** after some data is stored in output.
  205. ** "maxOutputLen" the maximum amount of data that can ever be
  206. ** stored in "output"
  207. ** "input" the input data
  208. ** "inputLen" the amount of input data
  209. */
  210. extern SECStatus
  211. AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
  212. unsigned int *pOutputLen, unsigned int maxOutputLen,
  213. const unsigned char *input, unsigned int inputLen)
  214. {
  215. PRUint64 * R = NULL;
  216. unsigned int nBlocks;
  217. unsigned int i, j;
  218. unsigned int aesLen = AES_BLOCK_SIZE;
  219. unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE;
  220. SECStatus s = SECFailure;
  221. /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
  222. PRUint64 t;
  223. PRUint64 B[2];
  224. #define A B[0]
  225. /* Check args */
  226. if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
  227. PORT_SetError(SEC_ERROR_INPUT_LEN);
  228. return s;
  229. }
  230. #ifdef maybe
  231. if (!output && pOutputLen) { /* caller is asking for output size */
  232. *pOutputLen = outLen;
  233. return SECSuccess;
  234. }
  235. #endif
  236. if (maxOutputLen < outLen) {
  237. PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  238. return s;
  239. }
  240. if (cx == NULL || output == NULL || input == NULL) {
  241. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  242. return s;
  243. }
  244. nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
  245. R = PORT_NewArray(PRUint64, nBlocks + 1);
  246. if (!R)
  247. return s; /* error is already set. */
  248. /*
  249. ** 1) Initialize variables.
  250. */
  251. memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
  252. memcpy(&R[1], input, inputLen);
  253. #if BIG_ENDIAN_WITH_64_BIT_REGISTERS
  254. t = 0;
  255. #else
  256. memset(&t, 0, sizeof t);
  257. #endif
  258. /*
  259. ** 2) Calculate intermediate values.
  260. */
  261. for (j = 0; j < 6; ++j) {
  262. for (i = 1; i <= nBlocks; ++i) {
  263. B[1] = R[i];
  264. s = AES_Encrypt(&cx->aescx, (unsigned char *)B, &aesLen,
  265. sizeof B, (unsigned char *)B, sizeof B);
  266. if (s != SECSuccess)
  267. break;
  268. R[i] = B[1];
  269. /* here, increment t and XOR A with t (in big endian order); */
  270. #if BIG_ENDIAN_WITH_64_BIT_REGISTERS
  271. A ^= ++t;
  272. #else
  273. increment_and_xor((unsigned char *)&A, (unsigned char *)&t);
  274. #endif
  275. }
  276. }
  277. /*
  278. ** 3) Output the results.
  279. */
  280. if (s == SECSuccess) {
  281. R[0] = A;
  282. memcpy(output, &R[0], outLen);
  283. if (pOutputLen)
  284. *pOutputLen = outLen;
  285. } else if (pOutputLen) {
  286. *pOutputLen = 0;
  287. }
  288. PORT_ZFree(R, outLen);
  289. return s;
  290. }
  291. #undef A
  292. /*
  293. ** Perform AES key unwrap.
  294. ** "cx" the context
  295. ** "output" the output buffer to store the decrypted data.
  296. ** "outputLen" how much data is stored in "output". Set by the routine
  297. ** after some data is stored in output.
  298. ** "maxOutputLen" the maximum amount of data that can ever be
  299. ** stored in "output"
  300. ** "input" the input data
  301. ** "inputLen" the amount of input data
  302. */
  303. extern SECStatus
  304. AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
  305. unsigned int *pOutputLen, unsigned int maxOutputLen,
  306. const unsigned char *input, unsigned int inputLen)
  307. {
  308. PRUint64 * R = NULL;
  309. unsigned int nBlocks;
  310. unsigned int i, j;
  311. unsigned int aesLen = AES_BLOCK_SIZE;
  312. unsigned int outLen;
  313. SECStatus s = SECFailure;
  314. /* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
  315. PRUint64 t;
  316. PRUint64 B[2];
  317. #define A B[0]
  318. /* Check args */
  319. if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE ||
  320. 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
  321. PORT_SetError(SEC_ERROR_INPUT_LEN);
  322. return s;
  323. }
  324. outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
  325. #ifdef maybe
  326. if (!output && pOutputLen) { /* caller is asking for output size */
  327. *pOutputLen = outLen;
  328. return SECSuccess;
  329. }
  330. #endif
  331. if (maxOutputLen < outLen) {
  332. PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  333. return s;
  334. }
  335. if (cx == NULL || output == NULL || input == NULL) {
  336. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  337. return s;
  338. }
  339. nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
  340. R = PORT_NewArray(PRUint64, nBlocks);
  341. if (!R)
  342. return s; /* error is already set. */
  343. nBlocks--;
  344. /*
  345. ** 1) Initialize variables.
  346. */
  347. memcpy(&R[0], input, inputLen);
  348. A = R[0];
  349. #if BIG_ENDIAN_WITH_64_BIT_REGISTERS
  350. t = 6UL * nBlocks;
  351. #else
  352. set_t((unsigned char *)&t, 6UL * nBlocks);
  353. #endif
  354. /*
  355. ** 2) Calculate intermediate values.
  356. */
  357. for (j = 0; j < 6; ++j) {
  358. for (i = nBlocks; i; --i) {
  359. /* here, XOR A with t (in big endian order) and decrement t; */
  360. #if BIG_ENDIAN_WITH_64_BIT_REGISTERS
  361. A ^= t--;
  362. #else
  363. xor_and_decrement((unsigned char *)&A, (unsigned char *)&t);
  364. #endif
  365. B[1] = R[i];
  366. s = AES_Decrypt(&cx->aescx, (unsigned char *)B, &aesLen,
  367. sizeof B, (unsigned char *)B, sizeof B);
  368. if (s != SECSuccess)
  369. break;
  370. R[i] = B[1];
  371. }
  372. }
  373. /*
  374. ** 3) Output the results.
  375. */
  376. if (s == SECSuccess) {
  377. int bad = memcmp(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
  378. if (!bad) {
  379. memcpy(output, &R[1], outLen);
  380. if (pOutputLen)
  381. *pOutputLen = outLen;
  382. } else {
  383. PORT_SetError(SEC_ERROR_BAD_DATA);
  384. if (pOutputLen)
  385. *pOutputLen = 0;
  386. }
  387. } else if (pOutputLen) {
  388. *pOutputLen = 0;
  389. }
  390. PORT_ZFree(R, inputLen);
  391. return s;
  392. }
  393. #undef A