cmscipher.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. /*
  5. * Encryption/decryption routines for CMS implementation, none of which are exported.
  6. */
  7. #include "cmslocal.h"
  8. #include "secoid.h"
  9. #include "secitem.h"
  10. #include "pk11func.h"
  11. #include "secerr.h"
  12. #include "secpkcs5.h"
  13. /*
  14. * -------------------------------------------------------------------
  15. * Cipher stuff.
  16. */
  17. typedef SECStatus (*nss_cms_cipher_function)(void *, unsigned char *, unsigned int *,
  18. unsigned int, const unsigned char *, unsigned int);
  19. typedef SECStatus (*nss_cms_cipher_destroy)(void *, PRBool);
  20. #define BLOCK_SIZE 4096
  21. struct NSSCMSCipherContextStr {
  22. void *cx; /* PK11 cipher context */
  23. nss_cms_cipher_function doit;
  24. nss_cms_cipher_destroy destroy;
  25. PRBool encrypt; /* encrypt / decrypt switch */
  26. int block_size; /* block & pad sizes for cipher */
  27. int pad_size;
  28. int pending_count; /* pending data (not yet en/decrypted */
  29. unsigned char pending_buf[BLOCK_SIZE]; /* because of blocking */
  30. };
  31. /*
  32. * NSS_CMSCipherContext_StartDecrypt - create a cipher context to do decryption
  33. * based on the given bulk encryption key and algorithm identifier (which
  34. * may include an iv).
  35. *
  36. * XXX Once both are working, it might be nice to combine this and the
  37. * function below (for starting up encryption) into one routine, and just
  38. * have two simple cover functions which call it.
  39. */
  40. NSSCMSCipherContext *
  41. NSS_CMSCipherContext_StartDecrypt(PK11SymKey *key, SECAlgorithmID *algid)
  42. {
  43. NSSCMSCipherContext *cc;
  44. void *ciphercx;
  45. CK_MECHANISM_TYPE cryptoMechType;
  46. PK11SlotInfo *slot;
  47. SECOidTag algtag;
  48. SECItem *param = NULL;
  49. algtag = SECOID_GetAlgorithmTag(algid);
  50. /* set param and mechanism */
  51. if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
  52. SECItem *pwitem;
  53. pwitem = PK11_GetSymKeyUserData(key);
  54. if (!pwitem)
  55. return NULL;
  56. cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
  57. if (cryptoMechType == CKM_INVALID_MECHANISM) {
  58. SECITEM_FreeItem(param, PR_TRUE);
  59. return NULL;
  60. }
  61. } else {
  62. cryptoMechType = PK11_AlgtagToMechanism(algtag);
  63. if ((param = PK11_ParamFromAlgid(algid)) == NULL)
  64. return NULL;
  65. }
  66. cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext));
  67. if (cc == NULL) {
  68. SECITEM_FreeItem(param, PR_TRUE);
  69. return NULL;
  70. }
  71. /* figure out pad and block sizes */
  72. cc->pad_size = PK11_GetBlockSize(cryptoMechType, param);
  73. slot = PK11_GetSlotFromKey(key);
  74. cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
  75. PK11_FreeSlot(slot);
  76. /* create PK11 cipher context */
  77. ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
  78. key, param);
  79. SECITEM_FreeItem(param, PR_TRUE);
  80. if (ciphercx == NULL) {
  81. PORT_Free(cc);
  82. return NULL;
  83. }
  84. cc->cx = ciphercx;
  85. cc->doit = (nss_cms_cipher_function)PK11_CipherOp;
  86. cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext;
  87. cc->encrypt = PR_FALSE;
  88. cc->pending_count = 0;
  89. return cc;
  90. }
  91. /*
  92. * NSS_CMSCipherContext_StartEncrypt - create a cipher object to do encryption,
  93. * based on the given bulk encryption key and algorithm tag. Fill in the
  94. * algorithm identifier (which may include an iv) appropriately.
  95. *
  96. * XXX Once both are working, it might be nice to combine this and the
  97. * function above (for starting up decryption) into one routine, and just
  98. * have two simple cover functions which call it.
  99. */
  100. NSSCMSCipherContext *
  101. NSS_CMSCipherContext_StartEncrypt(PLArenaPool *poolp, PK11SymKey *key, SECAlgorithmID *algid)
  102. {
  103. NSSCMSCipherContext *cc;
  104. void *ciphercx = NULL;
  105. SECStatus rv;
  106. CK_MECHANISM_TYPE cryptoMechType;
  107. PK11SlotInfo *slot;
  108. SECItem *param = NULL;
  109. PRBool needToEncodeAlgid = PR_FALSE;
  110. SECOidTag algtag = SECOID_GetAlgorithmTag(algid);
  111. /* set param and mechanism */
  112. if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
  113. SECItem *pwitem;
  114. pwitem = PK11_GetSymKeyUserData(key);
  115. if (!pwitem)
  116. return NULL;
  117. cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
  118. if (cryptoMechType == CKM_INVALID_MECHANISM) {
  119. SECITEM_FreeItem(param, PR_TRUE);
  120. return NULL;
  121. }
  122. } else {
  123. cryptoMechType = PK11_AlgtagToMechanism(algtag);
  124. if ((param = PK11_GenerateNewParam(cryptoMechType, key)) == NULL)
  125. return NULL;
  126. needToEncodeAlgid = PR_TRUE;
  127. }
  128. cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext));
  129. if (cc == NULL) {
  130. goto loser;
  131. }
  132. /* now find pad and block sizes for our mechanism */
  133. cc->pad_size = PK11_GetBlockSize(cryptoMechType, param);
  134. slot = PK11_GetSlotFromKey(key);
  135. cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
  136. PK11_FreeSlot(slot);
  137. /* and here we go, creating a PK11 cipher context */
  138. ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
  139. key, param);
  140. if (ciphercx == NULL) {
  141. PORT_Free(cc);
  142. cc = NULL;
  143. goto loser;
  144. }
  145. /*
  146. * These are placed after the CreateContextBySymKey() because some
  147. * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
  148. * Don't move it from here.
  149. * XXX is that right? the purpose of this is to get the correct algid
  150. * containing the IVs etc. for encoding. this means we need to set this up
  151. * BEFORE encoding the algid in the contentInfo, right?
  152. */
  153. if (needToEncodeAlgid) {
  154. rv = PK11_ParamToAlgid(algtag, param, poolp, algid);
  155. if (rv != SECSuccess) {
  156. PORT_Free(cc);
  157. cc = NULL;
  158. goto loser;
  159. }
  160. }
  161. cc->cx = ciphercx;
  162. ciphercx = NULL;
  163. cc->doit = (nss_cms_cipher_function)PK11_CipherOp;
  164. cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext;
  165. cc->encrypt = PR_TRUE;
  166. cc->pending_count = 0;
  167. loser:
  168. SECITEM_FreeItem(param, PR_TRUE);
  169. if (ciphercx) {
  170. PK11_DestroyContext(ciphercx, PR_TRUE);
  171. }
  172. return cc;
  173. }
  174. void
  175. NSS_CMSCipherContext_Destroy(NSSCMSCipherContext *cc)
  176. {
  177. PORT_Assert(cc != NULL);
  178. if (cc == NULL)
  179. return;
  180. (*cc->destroy)(cc->cx, PR_TRUE);
  181. PORT_Free(cc);
  182. }
  183. /*
  184. * NSS_CMSCipherContext_DecryptLength - find the output length of the next call to decrypt.
  185. *
  186. * cc - the cipher context
  187. * input_len - number of bytes used as input
  188. * final - true if this is the final chunk of data
  189. *
  190. * Result can be used to perform memory allocations. Note that the amount
  191. * is exactly accurate only when not doing a block cipher or when final
  192. * is false, otherwise it is an upper bound on the amount because until
  193. * we see the data we do not know how many padding bytes there are
  194. * (always between 1 and bsize).
  195. *
  196. * Note that this can return zero, which does not mean that the decrypt
  197. * operation can be skipped! (It simply means that there are not enough
  198. * bytes to make up an entire block; the bytes will be reserved until
  199. * there are enough to encrypt/decrypt at least one block.) However,
  200. * if zero is returned it *does* mean that no output buffer need be
  201. * passed in to the subsequent decrypt operation, as no output bytes
  202. * will be stored.
  203. */
  204. unsigned int
  205. NSS_CMSCipherContext_DecryptLength(NSSCMSCipherContext *cc, unsigned int input_len, PRBool final)
  206. {
  207. int blocks, block_size;
  208. PORT_Assert(!cc->encrypt);
  209. block_size = cc->block_size;
  210. /*
  211. * If this is not a block cipher, then we always have the same
  212. * number of output bytes as we had input bytes.
  213. */
  214. if (block_size == 0)
  215. return input_len;
  216. /*
  217. * On the final call, we will always use up all of the pending
  218. * bytes plus all of the input bytes, *but*, there will be padding
  219. * at the end and we cannot predict how many bytes of padding we
  220. * will end up removing. The amount given here is actually known
  221. * to be at least 1 byte too long (because we know we will have
  222. * at least 1 byte of padding), but seemed clearer/better to me.
  223. */
  224. if (final)
  225. return cc->pending_count + input_len;
  226. /*
  227. * Okay, this amount is exactly what we will output on the
  228. * next cipher operation. We will always hang onto the last
  229. * 1 - block_size bytes for non-final operations. That is,
  230. * we will do as many complete blocks as we can *except* the
  231. * last block (complete or partial). (This is because until
  232. * we know we are at the end, we cannot know when to interpret
  233. * and removing the padding byte(s), which are guaranteed to
  234. * be there.)
  235. */
  236. blocks = (cc->pending_count + input_len - 1) / block_size;
  237. return blocks * block_size;
  238. }
  239. /*
  240. * NSS_CMSCipherContext_EncryptLength - find the output length of the next call to encrypt.
  241. *
  242. * cc - the cipher context
  243. * input_len - number of bytes used as input
  244. * final - true if this is the final chunk of data
  245. *
  246. * Result can be used to perform memory allocations.
  247. *
  248. * Note that this can return zero, which does not mean that the encrypt
  249. * operation can be skipped! (It simply means that there are not enough
  250. * bytes to make up an entire block; the bytes will be reserved until
  251. * there are enough to encrypt/decrypt at least one block.) However,
  252. * if zero is returned it *does* mean that no output buffer need be
  253. * passed in to the subsequent encrypt operation, as no output bytes
  254. * will be stored.
  255. */
  256. unsigned int
  257. NSS_CMSCipherContext_EncryptLength(NSSCMSCipherContext *cc, unsigned int input_len, PRBool final)
  258. {
  259. int blocks, block_size;
  260. int pad_size;
  261. PORT_Assert(cc->encrypt);
  262. block_size = cc->block_size;
  263. pad_size = cc->pad_size;
  264. /*
  265. * If this is not a block cipher, then we always have the same
  266. * number of output bytes as we had input bytes.
  267. */
  268. if (block_size == 0)
  269. return input_len;
  270. /*
  271. * On the final call, we only send out what we need for
  272. * remaining bytes plus the padding. (There is always padding,
  273. * so even if we have an exact number of blocks as input, we
  274. * will add another full block that is just padding.)
  275. */
  276. if (final) {
  277. if (pad_size == 0) {
  278. return cc->pending_count + input_len;
  279. } else {
  280. blocks = (cc->pending_count + input_len) / pad_size;
  281. blocks++;
  282. return blocks * pad_size;
  283. }
  284. }
  285. /*
  286. * Now, count the number of complete blocks of data we have.
  287. */
  288. blocks = (cc->pending_count + input_len) / block_size;
  289. return blocks * block_size;
  290. }
  291. /*
  292. * NSS_CMSCipherContext_Decrypt - do the decryption
  293. *
  294. * cc - the cipher context
  295. * output - buffer for decrypted result bytes
  296. * output_len_p - number of bytes in output
  297. * max_output_len - upper bound on bytes to put into output
  298. * input - pointer to input bytes
  299. * input_len - number of input bytes
  300. * final - true if this is the final chunk of data
  301. *
  302. * Decrypts a given length of input buffer (starting at "input" and
  303. * containing "input_len" bytes), placing the decrypted bytes in
  304. * "output" and storing the output length in "*output_len_p".
  305. * "cc" is the return value from NSS_CMSCipher_StartDecrypt.
  306. * When "final" is true, this is the last of the data to be decrypted.
  307. *
  308. * This is much more complicated than it sounds when the cipher is
  309. * a block-type, meaning that the decryption function will only
  310. * operate on whole blocks. But our caller is operating stream-wise,
  311. * and can pass in any number of bytes. So we need to keep track
  312. * of block boundaries. We save excess bytes between calls in "cc".
  313. * We also need to determine which bytes are padding, and remove
  314. * them from the output. We can only do this step when we know we
  315. * have the final block of data. PKCS #7 specifies that the padding
  316. * used for a block cipher is a string of bytes, each of whose value is
  317. * the same as the length of the padding, and that all data is padded.
  318. * (Even data that starts out with an exact multiple of blocks gets
  319. * added to it another block, all of which is padding.)
  320. */
  321. SECStatus
  322. NSS_CMSCipherContext_Decrypt(NSSCMSCipherContext *cc, unsigned char *output,
  323. unsigned int *output_len_p, unsigned int max_output_len,
  324. const unsigned char *input, unsigned int input_len,
  325. PRBool final)
  326. {
  327. unsigned int blocks, bsize, pcount, padsize;
  328. unsigned int max_needed, ifraglen, ofraglen, output_len;
  329. unsigned char *pbuf;
  330. SECStatus rv;
  331. PORT_Assert(!cc->encrypt);
  332. /*
  333. * Check that we have enough room for the output. Our caller should
  334. * already handle this; failure is really an internal error (i.e. bug).
  335. */
  336. max_needed = NSS_CMSCipherContext_DecryptLength(cc, input_len, final);
  337. PORT_Assert(max_output_len >= max_needed);
  338. if (max_output_len < max_needed) {
  339. /* PORT_SetError (XXX); */
  340. return SECFailure;
  341. }
  342. /*
  343. * hardware encryption does not like small decryption sizes here, so we
  344. * allow both blocking and padding.
  345. */
  346. bsize = cc->block_size;
  347. padsize = cc->pad_size;
  348. /*
  349. * When no blocking or padding work to do, we can simply call the
  350. * cipher function and we are done.
  351. */
  352. if (bsize == 0) {
  353. return (*cc->doit)(cc->cx, output, output_len_p, max_output_len,
  354. input, input_len);
  355. }
  356. pcount = cc->pending_count;
  357. pbuf = cc->pending_buf;
  358. output_len = 0;
  359. if (pcount) {
  360. /*
  361. * Try to fill in an entire block, starting with the bytes
  362. * we already have saved away.
  363. */
  364. while (input_len && pcount < bsize) {
  365. pbuf[pcount++] = *input++;
  366. input_len--;
  367. }
  368. /*
  369. * If we have at most a whole block and this is not our last call,
  370. * then we are done for now. (We do not try to decrypt a lone
  371. * single block because we cannot interpret the padding bytes
  372. * until we know we are handling the very last block of all input.)
  373. */
  374. if (input_len == 0 && !final) {
  375. cc->pending_count = pcount;
  376. if (output_len_p)
  377. *output_len_p = 0;
  378. return SECSuccess;
  379. }
  380. /*
  381. * Given the logic above, we expect to have a full block by now.
  382. * If we do not, there is something wrong, either with our own
  383. * logic or with (length of) the data given to us.
  384. */
  385. if ((padsize != 0) && (pcount % padsize) != 0) {
  386. PORT_Assert(final);
  387. PORT_SetError(SEC_ERROR_BAD_DATA);
  388. return SECFailure;
  389. }
  390. /*
  391. * Decrypt the block.
  392. */
  393. rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
  394. pbuf, pcount);
  395. if (rv != SECSuccess)
  396. return rv;
  397. /*
  398. * For now anyway, all of our ciphers have the same number of
  399. * bytes of output as they do input. If this ever becomes untrue,
  400. * then NSS_CMSCipherContext_DecryptLength needs to be made smarter!
  401. */
  402. PORT_Assert(ofraglen == pcount);
  403. /*
  404. * Account for the bytes now in output.
  405. */
  406. max_output_len -= ofraglen;
  407. output_len += ofraglen;
  408. output += ofraglen;
  409. }
  410. /*
  411. * If this is our last call, we expect to have an exact number of
  412. * blocks left to be decrypted; we will decrypt them all.
  413. *
  414. * If not our last call, we always save between 1 and bsize bytes
  415. * until next time. (We must do this because we cannot be sure
  416. * that none of the decrypted bytes are padding bytes until we
  417. * have at least another whole block of data. You cannot tell by
  418. * looking -- the data could be anything -- you can only tell by
  419. * context, knowing you are looking at the last block.) We could
  420. * decrypt a whole block now but it is easier if we just treat it
  421. * the same way we treat partial block bytes.
  422. */
  423. if (final) {
  424. if (padsize) {
  425. blocks = input_len / padsize;
  426. ifraglen = blocks * padsize;
  427. } else
  428. ifraglen = input_len;
  429. PORT_Assert(ifraglen == input_len);
  430. if (ifraglen != input_len) {
  431. PORT_SetError(SEC_ERROR_BAD_DATA);
  432. return SECFailure;
  433. }
  434. } else {
  435. blocks = (input_len - 1) / bsize;
  436. ifraglen = blocks * bsize;
  437. PORT_Assert(ifraglen < input_len);
  438. pcount = input_len - ifraglen;
  439. PORT_Memcpy(pbuf, input + ifraglen, pcount);
  440. cc->pending_count = pcount;
  441. }
  442. if (ifraglen) {
  443. rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
  444. input, ifraglen);
  445. if (rv != SECSuccess)
  446. return rv;
  447. /*
  448. * For now anyway, all of our ciphers have the same number of
  449. * bytes of output as they do input. If this ever becomes untrue,
  450. * then sec_PKCS7DecryptLength needs to be made smarter!
  451. */
  452. PORT_Assert(ifraglen == ofraglen);
  453. if (ifraglen != ofraglen) {
  454. PORT_SetError(SEC_ERROR_BAD_DATA);
  455. return SECFailure;
  456. }
  457. output_len += ofraglen;
  458. } else {
  459. ofraglen = 0;
  460. }
  461. /*
  462. * If we just did our very last block, "remove" the padding by
  463. * adjusting the output length.
  464. */
  465. if (final && (padsize != 0)) {
  466. unsigned int padlen = *(output + ofraglen - 1);
  467. if (padlen == 0 || padlen > padsize) {
  468. PORT_SetError(SEC_ERROR_BAD_DATA);
  469. return SECFailure;
  470. }
  471. output_len -= padlen;
  472. }
  473. PORT_Assert(output_len_p != NULL || output_len == 0);
  474. if (output_len_p != NULL)
  475. *output_len_p = output_len;
  476. return SECSuccess;
  477. }
  478. /*
  479. * NSS_CMSCipherContext_Encrypt - do the encryption
  480. *
  481. * cc - the cipher context
  482. * output - buffer for decrypted result bytes
  483. * output_len_p - number of bytes in output
  484. * max_output_len - upper bound on bytes to put into output
  485. * input - pointer to input bytes
  486. * input_len - number of input bytes
  487. * final - true if this is the final chunk of data
  488. *
  489. * Encrypts a given length of input buffer (starting at "input" and
  490. * containing "input_len" bytes), placing the encrypted bytes in
  491. * "output" and storing the output length in "*output_len_p".
  492. * "cc" is the return value from NSS_CMSCipher_StartEncrypt.
  493. * When "final" is true, this is the last of the data to be encrypted.
  494. *
  495. * This is much more complicated than it sounds when the cipher is
  496. * a block-type, meaning that the encryption function will only
  497. * operate on whole blocks. But our caller is operating stream-wise,
  498. * and can pass in any number of bytes. So we need to keep track
  499. * of block boundaries. We save excess bytes between calls in "cc".
  500. * We also need to add padding bytes at the end. PKCS #7 specifies
  501. * that the padding used for a block cipher is a string of bytes,
  502. * each of whose value is the same as the length of the padding,
  503. * and that all data is padded. (Even data that starts out with
  504. * an exact multiple of blocks gets added to it another block,
  505. * all of which is padding.)
  506. *
  507. * XXX I would kind of like to combine this with the function above
  508. * which does decryption, since they have a lot in common. But the
  509. * tricky parts about padding and filling blocks would be much
  510. * harder to read that way, so I left them separate. At least for
  511. * now until it is clear that they are right.
  512. */
  513. SECStatus
  514. NSS_CMSCipherContext_Encrypt(NSSCMSCipherContext *cc, unsigned char *output,
  515. unsigned int *output_len_p, unsigned int max_output_len,
  516. const unsigned char *input, unsigned int input_len,
  517. PRBool final)
  518. {
  519. int blocks, bsize, padlen, pcount, padsize;
  520. unsigned int max_needed, ifraglen, ofraglen, output_len;
  521. unsigned char *pbuf;
  522. SECStatus rv;
  523. PORT_Assert(cc->encrypt);
  524. /*
  525. * Check that we have enough room for the output. Our caller should
  526. * already handle this; failure is really an internal error (i.e. bug).
  527. */
  528. max_needed = NSS_CMSCipherContext_EncryptLength(cc, input_len, final);
  529. PORT_Assert(max_output_len >= max_needed);
  530. if (max_output_len < max_needed) {
  531. /* PORT_SetError (XXX); */
  532. return SECFailure;
  533. }
  534. bsize = cc->block_size;
  535. padsize = cc->pad_size;
  536. /*
  537. * When no blocking and padding work to do, we can simply call the
  538. * cipher function and we are done.
  539. */
  540. if (bsize == 0) {
  541. return (*cc->doit)(cc->cx, output, output_len_p, max_output_len,
  542. input, input_len);
  543. }
  544. pcount = cc->pending_count;
  545. pbuf = cc->pending_buf;
  546. output_len = 0;
  547. if (pcount) {
  548. /*
  549. * Try to fill in an entire block, starting with the bytes
  550. * we already have saved away.
  551. */
  552. while (input_len && pcount < bsize) {
  553. pbuf[pcount++] = *input++;
  554. input_len--;
  555. }
  556. /*
  557. * If we do not have a full block and we know we will be
  558. * called again, then we are done for now.
  559. */
  560. if (pcount < bsize && !final) {
  561. cc->pending_count = pcount;
  562. if (output_len_p != NULL)
  563. *output_len_p = 0;
  564. return SECSuccess;
  565. }
  566. /*
  567. * If we have a whole block available, encrypt it.
  568. */
  569. if ((padsize == 0) || (pcount % padsize) == 0) {
  570. rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
  571. pbuf, pcount);
  572. if (rv != SECSuccess)
  573. return rv;
  574. /*
  575. * For now anyway, all of our ciphers have the same number of
  576. * bytes of output as they do input. If this ever becomes untrue,
  577. * then sec_PKCS7EncryptLength needs to be made smarter!
  578. */
  579. PORT_Assert(ofraglen == pcount);
  580. /*
  581. * Account for the bytes now in output.
  582. */
  583. max_output_len -= ofraglen;
  584. output_len += ofraglen;
  585. output += ofraglen;
  586. pcount = 0;
  587. }
  588. }
  589. if (input_len) {
  590. PORT_Assert(pcount == 0);
  591. blocks = input_len / bsize;
  592. ifraglen = blocks * bsize;
  593. if (ifraglen) {
  594. rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
  595. input, ifraglen);
  596. if (rv != SECSuccess)
  597. return rv;
  598. /*
  599. * For now anyway, all of our ciphers have the same number of
  600. * bytes of output as they do input. If this ever becomes untrue,
  601. * then sec_PKCS7EncryptLength needs to be made smarter!
  602. */
  603. PORT_Assert(ifraglen == ofraglen);
  604. max_output_len -= ofraglen;
  605. output_len += ofraglen;
  606. output += ofraglen;
  607. }
  608. pcount = input_len - ifraglen;
  609. PORT_Assert(pcount < bsize);
  610. if (pcount)
  611. PORT_Memcpy(pbuf, input + ifraglen, pcount);
  612. }
  613. if (final) {
  614. if (padsize <= 0) {
  615. padlen = 0;
  616. } else {
  617. padlen = padsize - (pcount % padsize);
  618. PORT_Memset(pbuf + pcount, padlen, padlen);
  619. }
  620. rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len,
  621. pbuf, pcount + padlen);
  622. if (rv != SECSuccess)
  623. return rv;
  624. /*
  625. * For now anyway, all of our ciphers have the same number of
  626. * bytes of output as they do input. If this ever becomes untrue,
  627. * then sec_PKCS7EncryptLength needs to be made smarter!
  628. */
  629. PORT_Assert(ofraglen == (pcount + padlen));
  630. output_len += ofraglen;
  631. } else {
  632. cc->pending_count = pcount;
  633. }
  634. PORT_Assert(output_len_p != NULL || output_len == 0);
  635. if (output_len_p != NULL)
  636. *output_len_p = output_len;
  637. return SECSuccess;
  638. }