1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/smime/cmscipher.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,715 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * Encryption/decryption routines for CMS implementation, none of which are exported. 1.10 + */ 1.11 + 1.12 +#include "cmslocal.h" 1.13 + 1.14 +#include "secoid.h" 1.15 +#include "secitem.h" 1.16 +#include "pk11func.h" 1.17 +#include "secerr.h" 1.18 +#include "secpkcs5.h" 1.19 + 1.20 +/* 1.21 + * ------------------------------------------------------------------- 1.22 + * Cipher stuff. 1.23 + */ 1.24 + 1.25 +typedef SECStatus (*nss_cms_cipher_function) (void *, unsigned char *, unsigned int *, 1.26 + unsigned int, const unsigned char *, unsigned int); 1.27 +typedef SECStatus (*nss_cms_cipher_destroy) (void *, PRBool); 1.28 + 1.29 +#define BLOCK_SIZE 4096 1.30 + 1.31 +struct NSSCMSCipherContextStr { 1.32 + void * cx; /* PK11 cipher context */ 1.33 + nss_cms_cipher_function doit; 1.34 + nss_cms_cipher_destroy destroy; 1.35 + PRBool encrypt; /* encrypt / decrypt switch */ 1.36 + int block_size; /* block & pad sizes for cipher */ 1.37 + int pad_size; 1.38 + int pending_count; /* pending data (not yet en/decrypted */ 1.39 + unsigned char pending_buf[BLOCK_SIZE];/* because of blocking */ 1.40 +}; 1.41 + 1.42 +/* 1.43 + * NSS_CMSCipherContext_StartDecrypt - create a cipher context to do decryption 1.44 + * based on the given bulk encryption key and algorithm identifier (which 1.45 + * may include an iv). 1.46 + * 1.47 + * XXX Once both are working, it might be nice to combine this and the 1.48 + * function below (for starting up encryption) into one routine, and just 1.49 + * have two simple cover functions which call it. 1.50 + */ 1.51 +NSSCMSCipherContext * 1.52 +NSS_CMSCipherContext_StartDecrypt(PK11SymKey *key, SECAlgorithmID *algid) 1.53 +{ 1.54 + NSSCMSCipherContext *cc; 1.55 + void *ciphercx; 1.56 + CK_MECHANISM_TYPE cryptoMechType; 1.57 + PK11SlotInfo *slot; 1.58 + SECOidTag algtag; 1.59 + SECItem *param = NULL; 1.60 + 1.61 + algtag = SECOID_GetAlgorithmTag(algid); 1.62 + 1.63 + /* set param and mechanism */ 1.64 + if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { 1.65 + SECItem *pwitem; 1.66 + 1.67 + pwitem = PK11_GetSymKeyUserData(key); 1.68 + if (!pwitem) 1.69 + return NULL; 1.70 + 1.71 + cryptoMechType = PK11_GetPBECryptoMechanism(algid, ¶m, pwitem); 1.72 + if (cryptoMechType == CKM_INVALID_MECHANISM) { 1.73 + SECITEM_FreeItem(param,PR_TRUE); 1.74 + return NULL; 1.75 + } 1.76 + 1.77 + } else { 1.78 + cryptoMechType = PK11_AlgtagToMechanism(algtag); 1.79 + if ((param = PK11_ParamFromAlgid(algid)) == NULL) 1.80 + return NULL; 1.81 + } 1.82 + 1.83 + cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext)); 1.84 + if (cc == NULL) { 1.85 + SECITEM_FreeItem(param,PR_TRUE); 1.86 + return NULL; 1.87 + } 1.88 + 1.89 + /* figure out pad and block sizes */ 1.90 + cc->pad_size = PK11_GetBlockSize(cryptoMechType, param); 1.91 + slot = PK11_GetSlotFromKey(key); 1.92 + cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; 1.93 + PK11_FreeSlot(slot); 1.94 + 1.95 + /* create PK11 cipher context */ 1.96 + ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, 1.97 + key, param); 1.98 + SECITEM_FreeItem(param, PR_TRUE); 1.99 + if (ciphercx == NULL) { 1.100 + PORT_Free (cc); 1.101 + return NULL; 1.102 + } 1.103 + 1.104 + cc->cx = ciphercx; 1.105 + cc->doit = (nss_cms_cipher_function) PK11_CipherOp; 1.106 + cc->destroy = (nss_cms_cipher_destroy) PK11_DestroyContext; 1.107 + cc->encrypt = PR_FALSE; 1.108 + cc->pending_count = 0; 1.109 + 1.110 + return cc; 1.111 +} 1.112 + 1.113 +/* 1.114 + * NSS_CMSCipherContext_StartEncrypt - create a cipher object to do encryption, 1.115 + * based on the given bulk encryption key and algorithm tag. Fill in the 1.116 + * algorithm identifier (which may include an iv) appropriately. 1.117 + * 1.118 + * XXX Once both are working, it might be nice to combine this and the 1.119 + * function above (for starting up decryption) into one routine, and just 1.120 + * have two simple cover functions which call it. 1.121 + */ 1.122 +NSSCMSCipherContext * 1.123 +NSS_CMSCipherContext_StartEncrypt(PLArenaPool *poolp, PK11SymKey *key, SECAlgorithmID *algid) 1.124 +{ 1.125 + NSSCMSCipherContext *cc; 1.126 + void *ciphercx; 1.127 + SECStatus rv; 1.128 + CK_MECHANISM_TYPE cryptoMechType; 1.129 + PK11SlotInfo *slot; 1.130 + SECItem *param = NULL; 1.131 + PRBool needToEncodeAlgid = PR_FALSE; 1.132 + SECOidTag algtag = SECOID_GetAlgorithmTag(algid); 1.133 + 1.134 + /* set param and mechanism */ 1.135 + if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) { 1.136 + SECItem *pwitem; 1.137 + 1.138 + pwitem = PK11_GetSymKeyUserData(key); 1.139 + if (!pwitem) 1.140 + return NULL; 1.141 + 1.142 + cryptoMechType = PK11_GetPBECryptoMechanism(algid, ¶m, pwitem); 1.143 + if (cryptoMechType == CKM_INVALID_MECHANISM) { 1.144 + SECITEM_FreeItem(param,PR_TRUE); 1.145 + return NULL; 1.146 + } 1.147 + } else { 1.148 + cryptoMechType = PK11_AlgtagToMechanism(algtag); 1.149 + if ((param = PK11_GenerateNewParam(cryptoMechType, key)) == NULL) 1.150 + return NULL; 1.151 + needToEncodeAlgid = PR_TRUE; 1.152 + } 1.153 + 1.154 + cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext)); 1.155 + if (cc == NULL) { 1.156 + goto loser; 1.157 + } 1.158 + 1.159 + /* now find pad and block sizes for our mechanism */ 1.160 + cc->pad_size = PK11_GetBlockSize(cryptoMechType, param); 1.161 + slot = PK11_GetSlotFromKey(key); 1.162 + cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size; 1.163 + PK11_FreeSlot(slot); 1.164 + 1.165 + /* and here we go, creating a PK11 cipher context */ 1.166 + ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, 1.167 + key, param); 1.168 + if (ciphercx == NULL) { 1.169 + PORT_Free(cc); 1.170 + cc = NULL; 1.171 + goto loser; 1.172 + } 1.173 + 1.174 + /* 1.175 + * These are placed after the CreateContextBySymKey() because some 1.176 + * mechanisms have to generate their IVs from their card (i.e. FORTEZZA). 1.177 + * Don't move it from here. 1.178 + * XXX is that right? the purpose of this is to get the correct algid 1.179 + * containing the IVs etc. for encoding. this means we need to set this up 1.180 + * BEFORE encoding the algid in the contentInfo, right? 1.181 + */ 1.182 + if (needToEncodeAlgid) { 1.183 + rv = PK11_ParamToAlgid(algtag, param, poolp, algid); 1.184 + if(rv != SECSuccess) { 1.185 + PORT_Free(cc); 1.186 + cc = NULL; 1.187 + goto loser; 1.188 + } 1.189 + } 1.190 + 1.191 + cc->cx = ciphercx; 1.192 + cc->doit = (nss_cms_cipher_function)PK11_CipherOp; 1.193 + cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext; 1.194 + cc->encrypt = PR_TRUE; 1.195 + cc->pending_count = 0; 1.196 + 1.197 +loser: 1.198 + SECITEM_FreeItem(param, PR_TRUE); 1.199 + 1.200 + return cc; 1.201 +} 1.202 + 1.203 +void 1.204 +NSS_CMSCipherContext_Destroy(NSSCMSCipherContext *cc) 1.205 +{ 1.206 + PORT_Assert(cc != NULL); 1.207 + if (cc == NULL) 1.208 + return; 1.209 + (*cc->destroy)(cc->cx, PR_TRUE); 1.210 + PORT_Free(cc); 1.211 +} 1.212 + 1.213 +/* 1.214 + * NSS_CMSCipherContext_DecryptLength - find the output length of the next call to decrypt. 1.215 + * 1.216 + * cc - the cipher context 1.217 + * input_len - number of bytes used as input 1.218 + * final - true if this is the final chunk of data 1.219 + * 1.220 + * Result can be used to perform memory allocations. Note that the amount 1.221 + * is exactly accurate only when not doing a block cipher or when final 1.222 + * is false, otherwise it is an upper bound on the amount because until 1.223 + * we see the data we do not know how many padding bytes there are 1.224 + * (always between 1 and bsize). 1.225 + * 1.226 + * Note that this can return zero, which does not mean that the decrypt 1.227 + * operation can be skipped! (It simply means that there are not enough 1.228 + * bytes to make up an entire block; the bytes will be reserved until 1.229 + * there are enough to encrypt/decrypt at least one block.) However, 1.230 + * if zero is returned it *does* mean that no output buffer need be 1.231 + * passed in to the subsequent decrypt operation, as no output bytes 1.232 + * will be stored. 1.233 + */ 1.234 +unsigned int 1.235 +NSS_CMSCipherContext_DecryptLength(NSSCMSCipherContext *cc, unsigned int input_len, PRBool final) 1.236 +{ 1.237 + int blocks, block_size; 1.238 + 1.239 + PORT_Assert (! cc->encrypt); 1.240 + 1.241 + block_size = cc->block_size; 1.242 + 1.243 + /* 1.244 + * If this is not a block cipher, then we always have the same 1.245 + * number of output bytes as we had input bytes. 1.246 + */ 1.247 + if (block_size == 0) 1.248 + return input_len; 1.249 + 1.250 + /* 1.251 + * On the final call, we will always use up all of the pending 1.252 + * bytes plus all of the input bytes, *but*, there will be padding 1.253 + * at the end and we cannot predict how many bytes of padding we 1.254 + * will end up removing. The amount given here is actually known 1.255 + * to be at least 1 byte too long (because we know we will have 1.256 + * at least 1 byte of padding), but seemed clearer/better to me. 1.257 + */ 1.258 + if (final) 1.259 + return cc->pending_count + input_len; 1.260 + 1.261 + /* 1.262 + * Okay, this amount is exactly what we will output on the 1.263 + * next cipher operation. We will always hang onto the last 1.264 + * 1 - block_size bytes for non-final operations. That is, 1.265 + * we will do as many complete blocks as we can *except* the 1.266 + * last block (complete or partial). (This is because until 1.267 + * we know we are at the end, we cannot know when to interpret 1.268 + * and removing the padding byte(s), which are guaranteed to 1.269 + * be there.) 1.270 + */ 1.271 + blocks = (cc->pending_count + input_len - 1) / block_size; 1.272 + return blocks * block_size; 1.273 +} 1.274 + 1.275 +/* 1.276 + * NSS_CMSCipherContext_EncryptLength - find the output length of the next call to encrypt. 1.277 + * 1.278 + * cc - the cipher context 1.279 + * input_len - number of bytes used as input 1.280 + * final - true if this is the final chunk of data 1.281 + * 1.282 + * Result can be used to perform memory allocations. 1.283 + * 1.284 + * Note that this can return zero, which does not mean that the encrypt 1.285 + * operation can be skipped! (It simply means that there are not enough 1.286 + * bytes to make up an entire block; the bytes will be reserved until 1.287 + * there are enough to encrypt/decrypt at least one block.) However, 1.288 + * if zero is returned it *does* mean that no output buffer need be 1.289 + * passed in to the subsequent encrypt operation, as no output bytes 1.290 + * will be stored. 1.291 + */ 1.292 +unsigned int 1.293 +NSS_CMSCipherContext_EncryptLength(NSSCMSCipherContext *cc, unsigned int input_len, PRBool final) 1.294 +{ 1.295 + int blocks, block_size; 1.296 + int pad_size; 1.297 + 1.298 + PORT_Assert (cc->encrypt); 1.299 + 1.300 + block_size = cc->block_size; 1.301 + pad_size = cc->pad_size; 1.302 + 1.303 + /* 1.304 + * If this is not a block cipher, then we always have the same 1.305 + * number of output bytes as we had input bytes. 1.306 + */ 1.307 + if (block_size == 0) 1.308 + return input_len; 1.309 + 1.310 + /* 1.311 + * On the final call, we only send out what we need for 1.312 + * remaining bytes plus the padding. (There is always padding, 1.313 + * so even if we have an exact number of blocks as input, we 1.314 + * will add another full block that is just padding.) 1.315 + */ 1.316 + if (final) { 1.317 + if (pad_size == 0) { 1.318 + return cc->pending_count + input_len; 1.319 + } else { 1.320 + blocks = (cc->pending_count + input_len) / pad_size; 1.321 + blocks++; 1.322 + return blocks*pad_size; 1.323 + } 1.324 + } 1.325 + 1.326 + /* 1.327 + * Now, count the number of complete blocks of data we have. 1.328 + */ 1.329 + blocks = (cc->pending_count + input_len) / block_size; 1.330 + 1.331 + 1.332 + return blocks * block_size; 1.333 +} 1.334 + 1.335 + 1.336 +/* 1.337 + * NSS_CMSCipherContext_Decrypt - do the decryption 1.338 + * 1.339 + * cc - the cipher context 1.340 + * output - buffer for decrypted result bytes 1.341 + * output_len_p - number of bytes in output 1.342 + * max_output_len - upper bound on bytes to put into output 1.343 + * input - pointer to input bytes 1.344 + * input_len - number of input bytes 1.345 + * final - true if this is the final chunk of data 1.346 + * 1.347 + * Decrypts a given length of input buffer (starting at "input" and 1.348 + * containing "input_len" bytes), placing the decrypted bytes in 1.349 + * "output" and storing the output length in "*output_len_p". 1.350 + * "cc" is the return value from NSS_CMSCipher_StartDecrypt. 1.351 + * When "final" is true, this is the last of the data to be decrypted. 1.352 + * 1.353 + * This is much more complicated than it sounds when the cipher is 1.354 + * a block-type, meaning that the decryption function will only 1.355 + * operate on whole blocks. But our caller is operating stream-wise, 1.356 + * and can pass in any number of bytes. So we need to keep track 1.357 + * of block boundaries. We save excess bytes between calls in "cc". 1.358 + * We also need to determine which bytes are padding, and remove 1.359 + * them from the output. We can only do this step when we know we 1.360 + * have the final block of data. PKCS #7 specifies that the padding 1.361 + * used for a block cipher is a string of bytes, each of whose value is 1.362 + * the same as the length of the padding, and that all data is padded. 1.363 + * (Even data that starts out with an exact multiple of blocks gets 1.364 + * added to it another block, all of which is padding.) 1.365 + */ 1.366 +SECStatus 1.367 +NSS_CMSCipherContext_Decrypt(NSSCMSCipherContext *cc, unsigned char *output, 1.368 + unsigned int *output_len_p, unsigned int max_output_len, 1.369 + const unsigned char *input, unsigned int input_len, 1.370 + PRBool final) 1.371 +{ 1.372 + int blocks, bsize, pcount, padsize; 1.373 + unsigned int max_needed, ifraglen, ofraglen, output_len; 1.374 + unsigned char *pbuf; 1.375 + SECStatus rv; 1.376 + 1.377 + PORT_Assert (! cc->encrypt); 1.378 + 1.379 + /* 1.380 + * Check that we have enough room for the output. Our caller should 1.381 + * already handle this; failure is really an internal error (i.e. bug). 1.382 + */ 1.383 + max_needed = NSS_CMSCipherContext_DecryptLength(cc, input_len, final); 1.384 + PORT_Assert (max_output_len >= max_needed); 1.385 + if (max_output_len < max_needed) { 1.386 + /* PORT_SetError (XXX); */ 1.387 + return SECFailure; 1.388 + } 1.389 + 1.390 + /* 1.391 + * hardware encryption does not like small decryption sizes here, so we 1.392 + * allow both blocking and padding. 1.393 + */ 1.394 + bsize = cc->block_size; 1.395 + padsize = cc->pad_size; 1.396 + 1.397 + /* 1.398 + * When no blocking or padding work to do, we can simply call the 1.399 + * cipher function and we are done. 1.400 + */ 1.401 + if (bsize == 0) { 1.402 + return (* cc->doit) (cc->cx, output, output_len_p, max_output_len, 1.403 + input, input_len); 1.404 + } 1.405 + 1.406 + pcount = cc->pending_count; 1.407 + pbuf = cc->pending_buf; 1.408 + 1.409 + output_len = 0; 1.410 + 1.411 + if (pcount) { 1.412 + /* 1.413 + * Try to fill in an entire block, starting with the bytes 1.414 + * we already have saved away. 1.415 + */ 1.416 + while (input_len && pcount < bsize) { 1.417 + pbuf[pcount++] = *input++; 1.418 + input_len--; 1.419 + } 1.420 + /* 1.421 + * If we have at most a whole block and this is not our last call, 1.422 + * then we are done for now. (We do not try to decrypt a lone 1.423 + * single block because we cannot interpret the padding bytes 1.424 + * until we know we are handling the very last block of all input.) 1.425 + */ 1.426 + if (input_len == 0 && !final) { 1.427 + cc->pending_count = pcount; 1.428 + if (output_len_p) 1.429 + *output_len_p = 0; 1.430 + return SECSuccess; 1.431 + } 1.432 + /* 1.433 + * Given the logic above, we expect to have a full block by now. 1.434 + * If we do not, there is something wrong, either with our own 1.435 + * logic or with (length of) the data given to us. 1.436 + */ 1.437 + if ((padsize != 0) && (pcount % padsize) != 0) { 1.438 + PORT_Assert (final); 1.439 + PORT_SetError (SEC_ERROR_BAD_DATA); 1.440 + return SECFailure; 1.441 + } 1.442 + /* 1.443 + * Decrypt the block. 1.444 + */ 1.445 + rv = (*cc->doit)(cc->cx, output, &ofraglen, max_output_len, 1.446 + pbuf, pcount); 1.447 + if (rv != SECSuccess) 1.448 + return rv; 1.449 + 1.450 + /* 1.451 + * For now anyway, all of our ciphers have the same number of 1.452 + * bytes of output as they do input. If this ever becomes untrue, 1.453 + * then NSS_CMSCipherContext_DecryptLength needs to be made smarter! 1.454 + */ 1.455 + PORT_Assert(ofraglen == pcount); 1.456 + 1.457 + /* 1.458 + * Account for the bytes now in output. 1.459 + */ 1.460 + max_output_len -= ofraglen; 1.461 + output_len += ofraglen; 1.462 + output += ofraglen; 1.463 + } 1.464 + 1.465 + /* 1.466 + * If this is our last call, we expect to have an exact number of 1.467 + * blocks left to be decrypted; we will decrypt them all. 1.468 + * 1.469 + * If not our last call, we always save between 1 and bsize bytes 1.470 + * until next time. (We must do this because we cannot be sure 1.471 + * that none of the decrypted bytes are padding bytes until we 1.472 + * have at least another whole block of data. You cannot tell by 1.473 + * looking -- the data could be anything -- you can only tell by 1.474 + * context, knowing you are looking at the last block.) We could 1.475 + * decrypt a whole block now but it is easier if we just treat it 1.476 + * the same way we treat partial block bytes. 1.477 + */ 1.478 + if (final) { 1.479 + if (padsize) { 1.480 + blocks = input_len / padsize; 1.481 + ifraglen = blocks * padsize; 1.482 + } else ifraglen = input_len; 1.483 + PORT_Assert (ifraglen == input_len); 1.484 + 1.485 + if (ifraglen != input_len) { 1.486 + PORT_SetError(SEC_ERROR_BAD_DATA); 1.487 + return SECFailure; 1.488 + } 1.489 + } else { 1.490 + blocks = (input_len - 1) / bsize; 1.491 + ifraglen = blocks * bsize; 1.492 + PORT_Assert (ifraglen < input_len); 1.493 + 1.494 + pcount = input_len - ifraglen; 1.495 + PORT_Memcpy (pbuf, input + ifraglen, pcount); 1.496 + cc->pending_count = pcount; 1.497 + } 1.498 + 1.499 + if (ifraglen) { 1.500 + rv = (* cc->doit)(cc->cx, output, &ofraglen, max_output_len, 1.501 + input, ifraglen); 1.502 + if (rv != SECSuccess) 1.503 + return rv; 1.504 + 1.505 + /* 1.506 + * For now anyway, all of our ciphers have the same number of 1.507 + * bytes of output as they do input. If this ever becomes untrue, 1.508 + * then sec_PKCS7DecryptLength needs to be made smarter! 1.509 + */ 1.510 + PORT_Assert (ifraglen == ofraglen); 1.511 + if (ifraglen != ofraglen) { 1.512 + PORT_SetError(SEC_ERROR_BAD_DATA); 1.513 + return SECFailure; 1.514 + } 1.515 + 1.516 + output_len += ofraglen; 1.517 + } else { 1.518 + ofraglen = 0; 1.519 + } 1.520 + 1.521 + /* 1.522 + * If we just did our very last block, "remove" the padding by 1.523 + * adjusting the output length. 1.524 + */ 1.525 + if (final && (padsize != 0)) { 1.526 + unsigned int padlen = *(output + ofraglen - 1); 1.527 + 1.528 + if (padlen == 0 || padlen > padsize) { 1.529 + PORT_SetError(SEC_ERROR_BAD_DATA); 1.530 + return SECFailure; 1.531 + } 1.532 + output_len -= padlen; 1.533 + } 1.534 + 1.535 + PORT_Assert (output_len_p != NULL || output_len == 0); 1.536 + if (output_len_p != NULL) 1.537 + *output_len_p = output_len; 1.538 + 1.539 + return SECSuccess; 1.540 +} 1.541 + 1.542 +/* 1.543 + * NSS_CMSCipherContext_Encrypt - do the encryption 1.544 + * 1.545 + * cc - the cipher context 1.546 + * output - buffer for decrypted result bytes 1.547 + * output_len_p - number of bytes in output 1.548 + * max_output_len - upper bound on bytes to put into output 1.549 + * input - pointer to input bytes 1.550 + * input_len - number of input bytes 1.551 + * final - true if this is the final chunk of data 1.552 + * 1.553 + * Encrypts a given length of input buffer (starting at "input" and 1.554 + * containing "input_len" bytes), placing the encrypted bytes in 1.555 + * "output" and storing the output length in "*output_len_p". 1.556 + * "cc" is the return value from NSS_CMSCipher_StartEncrypt. 1.557 + * When "final" is true, this is the last of the data to be encrypted. 1.558 + * 1.559 + * This is much more complicated than it sounds when the cipher is 1.560 + * a block-type, meaning that the encryption function will only 1.561 + * operate on whole blocks. But our caller is operating stream-wise, 1.562 + * and can pass in any number of bytes. So we need to keep track 1.563 + * of block boundaries. We save excess bytes between calls in "cc". 1.564 + * We also need to add padding bytes at the end. PKCS #7 specifies 1.565 + * that the padding used for a block cipher is a string of bytes, 1.566 + * each of whose value is the same as the length of the padding, 1.567 + * and that all data is padded. (Even data that starts out with 1.568 + * an exact multiple of blocks gets added to it another block, 1.569 + * all of which is padding.) 1.570 + * 1.571 + * XXX I would kind of like to combine this with the function above 1.572 + * which does decryption, since they have a lot in common. But the 1.573 + * tricky parts about padding and filling blocks would be much 1.574 + * harder to read that way, so I left them separate. At least for 1.575 + * now until it is clear that they are right. 1.576 + */ 1.577 +SECStatus 1.578 +NSS_CMSCipherContext_Encrypt(NSSCMSCipherContext *cc, unsigned char *output, 1.579 + unsigned int *output_len_p, unsigned int max_output_len, 1.580 + const unsigned char *input, unsigned int input_len, 1.581 + PRBool final) 1.582 +{ 1.583 + int blocks, bsize, padlen, pcount, padsize; 1.584 + unsigned int max_needed, ifraglen, ofraglen, output_len; 1.585 + unsigned char *pbuf; 1.586 + SECStatus rv; 1.587 + 1.588 + PORT_Assert (cc->encrypt); 1.589 + 1.590 + /* 1.591 + * Check that we have enough room for the output. Our caller should 1.592 + * already handle this; failure is really an internal error (i.e. bug). 1.593 + */ 1.594 + max_needed = NSS_CMSCipherContext_EncryptLength (cc, input_len, final); 1.595 + PORT_Assert (max_output_len >= max_needed); 1.596 + if (max_output_len < max_needed) { 1.597 + /* PORT_SetError (XXX); */ 1.598 + return SECFailure; 1.599 + } 1.600 + 1.601 + bsize = cc->block_size; 1.602 + padsize = cc->pad_size; 1.603 + 1.604 + /* 1.605 + * When no blocking and padding work to do, we can simply call the 1.606 + * cipher function and we are done. 1.607 + */ 1.608 + if (bsize == 0) { 1.609 + return (*cc->doit)(cc->cx, output, output_len_p, max_output_len, 1.610 + input, input_len); 1.611 + } 1.612 + 1.613 + pcount = cc->pending_count; 1.614 + pbuf = cc->pending_buf; 1.615 + 1.616 + output_len = 0; 1.617 + 1.618 + if (pcount) { 1.619 + /* 1.620 + * Try to fill in an entire block, starting with the bytes 1.621 + * we already have saved away. 1.622 + */ 1.623 + while (input_len && pcount < bsize) { 1.624 + pbuf[pcount++] = *input++; 1.625 + input_len--; 1.626 + } 1.627 + /* 1.628 + * If we do not have a full block and we know we will be 1.629 + * called again, then we are done for now. 1.630 + */ 1.631 + if (pcount < bsize && !final) { 1.632 + cc->pending_count = pcount; 1.633 + if (output_len_p != NULL) 1.634 + *output_len_p = 0; 1.635 + return SECSuccess; 1.636 + } 1.637 + /* 1.638 + * If we have a whole block available, encrypt it. 1.639 + */ 1.640 + if ((padsize == 0) || (pcount % padsize) == 0) { 1.641 + rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, 1.642 + pbuf, pcount); 1.643 + if (rv != SECSuccess) 1.644 + return rv; 1.645 + 1.646 + /* 1.647 + * For now anyway, all of our ciphers have the same number of 1.648 + * bytes of output as they do input. If this ever becomes untrue, 1.649 + * then sec_PKCS7EncryptLength needs to be made smarter! 1.650 + */ 1.651 + PORT_Assert (ofraglen == pcount); 1.652 + 1.653 + /* 1.654 + * Account for the bytes now in output. 1.655 + */ 1.656 + max_output_len -= ofraglen; 1.657 + output_len += ofraglen; 1.658 + output += ofraglen; 1.659 + 1.660 + pcount = 0; 1.661 + } 1.662 + } 1.663 + 1.664 + if (input_len) { 1.665 + PORT_Assert (pcount == 0); 1.666 + 1.667 + blocks = input_len / bsize; 1.668 + ifraglen = blocks * bsize; 1.669 + 1.670 + if (ifraglen) { 1.671 + rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, 1.672 + input, ifraglen); 1.673 + if (rv != SECSuccess) 1.674 + return rv; 1.675 + 1.676 + /* 1.677 + * For now anyway, all of our ciphers have the same number of 1.678 + * bytes of output as they do input. If this ever becomes untrue, 1.679 + * then sec_PKCS7EncryptLength needs to be made smarter! 1.680 + */ 1.681 + PORT_Assert (ifraglen == ofraglen); 1.682 + 1.683 + max_output_len -= ofraglen; 1.684 + output_len += ofraglen; 1.685 + output += ofraglen; 1.686 + } 1.687 + 1.688 + pcount = input_len - ifraglen; 1.689 + PORT_Assert (pcount < bsize); 1.690 + if (pcount) 1.691 + PORT_Memcpy (pbuf, input + ifraglen, pcount); 1.692 + } 1.693 + 1.694 + if (final) { 1.695 + padlen = padsize - (pcount % padsize); 1.696 + PORT_Memset (pbuf + pcount, padlen, padlen); 1.697 + rv = (* cc->doit) (cc->cx, output, &ofraglen, max_output_len, 1.698 + pbuf, pcount+padlen); 1.699 + if (rv != SECSuccess) 1.700 + return rv; 1.701 + 1.702 + /* 1.703 + * For now anyway, all of our ciphers have the same number of 1.704 + * bytes of output as they do input. If this ever becomes untrue, 1.705 + * then sec_PKCS7EncryptLength needs to be made smarter! 1.706 + */ 1.707 + PORT_Assert (ofraglen == (pcount+padlen)); 1.708 + output_len += ofraglen; 1.709 + } else { 1.710 + cc->pending_count = pcount; 1.711 + } 1.712 + 1.713 + PORT_Assert (output_len_p != NULL || output_len == 0); 1.714 + if (output_len_p != NULL) 1.715 + *output_len_p = output_len; 1.716 + 1.717 + return SECSuccess; 1.718 +}