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