📄 cbcmodem.nc
字号:
return SUCCESS; } // else we know there are 2 or more blocks (though the last one may be a // partial). dumpBuffer( "CBC.decrypt cipher:", cipherBlock, numBytes); // find the start of the last whole block: bc = bsize; while (bc < numBytes) bc += bsize; // and the block before it bc -= (bsize << 1); partialSize = numBytes - bc - bsize; dbg (DBG_CRYPTO, "CBC.decrypt bc: %d; partial %d \n", bc, partialSize); // split up the computation: depending on whether the last block // is full or not. if (partialSize) { // decrypt C_n if (call BlockCipher.decrypt (&context->cc, cipherBlock + bc, spillblock) != SUCCESS) { return FAIL; } // recover C_{n-1}, [in spillblock2] and P_{n} [in spillblock] for (i = 0; i < partialSize; i++) { // bit convoluted for the case where we // alias plainBlock and CipherBlock spillblock[i] ^= cipherBlock [bc + bsize + i]; spillblock2[i] = cipherBlock[bc + bsize + i]; plainBlock[bc + bsize + i] = spillblock[i]; } // copy over the remaining portion of the spillblock for (i = partialSize; i < bsize; i++) { spillblock2[i] = spillblock[i]; } // and decrypt the spillblock (C_{n-1}) into position. if (call BlockCipher.decrypt (&context->cc, spillblock2, plainBlock + bc) != SUCCESS) { return FAIL; } // NOW xor pref [iv or prev block]. We work from the end forward. // that happens after the if / else dumpBuffer ("CBC.decrypt partial", plainBlock, numBytes); } else { // bit simpler - just decrypt C_{n-1} into the spillblock if (call BlockCipher.decrypt (&context->cc, cipherBlock + bc, spillblock) != SUCCESS) { return FAIL; } // xor to recover C_{n} and decrypt into place for (i = 0; i < bsize; i++) { spillblock[i] ^= cipherBlock[bc + i + bsize]; } if (call BlockCipher.decrypt (&context->cc, cipherBlock + bc + bsize, plainBlock + bc) != SUCCESS) { return FAIL; } // copy P_{n-1} into place for (i = 0; i < bsize; i++) { plainBlock[bc + bsize + i] = spillblock[i]; } // NOW xor prev [iv or prev block in] } // handle blocks 0.. n-2 // by xoring in the n-1 ciphertext and decrypting. while (bc) { bc -= bsize; for (i = 0 ; i < bsize; i++) { plainBlock [ bc + bsize + i] ^= cipherBlock [bc + i]; } if (call BlockCipher.decrypt (&context->cc, cipherBlock + bc, plainBlock + bc) != SUCCESS) { return FAIL; } } // xor the iv to recover P_0 for (i = 0 ; i < bsize; i++) { plainBlock[i] ^= IV[i]; } dumpBuffer( "CBC.decrypt cipher:", plainBlock, numBytes); return SUCCESS; } /** * Initializes the mode for an incremental decryption operation. This step * is necessary for incremental decryption where the incoming data stream is * processed a byte at a time and cipher operations are done as soon as * possible. This is meant to allow for better overlapping of decryption * with a slower process that receives the encrypted stream (say via the * network ). * * This call may induce a block cipher call. * @param context holds the module specific opaque data related to the * key (perhaps key expansions) and other internal state. * @param IV The initialization vector that was used to encrypt this * particular data stream. This array must have a length equal to * one block size. * @param The exact length of the data stream in bytes; this must be at * least the underlying block cipher size. * @return Whether the initialization was successful. Possible failure * reasons include not calling init() or an underlying failure in the * block cipher. */ async command result_t BlockCipherMode.initIncrementalDecrypt ( CipherModeContext * context, uint8_t * IV, uint16_t length) { CBCModeContext * mcontext = (CBCModeContext*)(context->context); if (!length) return SUCCESS; if ( length < mcontext->bsize) return FAIL; mcontext->remaining = length; // decrypt the IV. if (call BlockCipher.encrypt (&context->cc, IV, mcontext->spill1) != SUCCESS) { return FAIL; } dumpBuffer ("E(IV)", mcontext->spill1, 8); // prime the pump: mcontext->offset = mcontext->completed = 0; // done amt mcontext->accum = FALSE; // figure out our state based on the amount of ciphertext that we're // gonna get: if (length == mcontext->bsize) { mcontext->state = ONE_BLOCK; } else if (length <= mcontext->bsize * 2) { mcontext->state = TWO_LEFT_A; } else { mcontext->state = GENERAL; } return SUCCESS; } /** * Performs an incremental decryption operation. It executes roughly one * block cipher call for every block's worth of ciphertext provided, placing * the result into the plaintext buffer. The done out parameter gives an * indication of the amount of data that has been successfully been * decrypted. * * @param context holds the module specific opaque data related to the * key (perhaps key expansions) and other internal state. * @param ciphertext Pointer to the start of the next ciphertext buffer. * @param plaintext Pointer to the start of the buffer which is large enough * to hold the entire ciphertext. This buffer must be passed in every * time to the incrementalDecrypt function. After this call, * <i>done</i> bytes of the plaintext buffer will be available for * consumption. * @param length The number of bytes that is being provided in the ciphertext * @param done A pointer to an int which will be filled in after the call * completes with the number of bytes of plaintext which is * available. * @return Whether the call was successful or not. Possible failure reasons * include not calling init(), an underlying failure in the block * cipher, or providing more ciphertext than is expected. */ async command result_t BlockCipherMode.incrementalDecrypt ( CipherModeContext * context, uint8_t * cipher, uint8_t * plain, uint16_t length, uint16_t * done) { CBCModeContext * mcontext = (CBCModeContext*)(context->context); int i, j; uint8_t * accum ; uint8_t * lastCipher ; uint8_t bsize = mcontext->bsize; uint16_t completed = mcontext->completed; // We run this deal as a simple state machine. See above for a diagram // of states and their transitions. // first, start with some simple checking: dbg(DBG_CRYPTO, "CBCModeM:incrementalDecrypt: <entry>length %d\n", length); if (!length) { *done = mcontext->completed; return SUCCESS; } if (length > mcontext->remaining) { dbg(DBG_CRYPTO,"Fail 1\n"); return FAIL; } while (length) { // determine which is the accumulator and which contains the previous // ciphertext. the accumulator is our temp storage space for the // current ciphertext. once it gets full, we decrypt it. if (mcontext->accum) { accum = mcontext->spill1; lastCipher = mcontext->spill2; } else { accum = mcontext->spill2; lastCipher = mcontext->spill1; } // all but the TWO_LEFT_B state can use this common code to populate // the accumulator witht he code from the ciphertext. if (mcontext->state != TWO_LEFT_B) { if (mcontext->offset + length < bsize) { // this means we haven't filled up a block. so we copy into the // accumulator, and update a few counters and ext. dbg(DBG_CRYPTO, "incrementalDecrypt: Moved %d; 0 left this run\n", length); memcpy(accum + mcontext->offset, cipher, length); *done = mcontext->completed = completed; mcontext->offset += length; mcontext->remaining -= length; return SUCCESS; } // we can fill up a block's worth of data. so do so, update some // state, and move on down to the appropriate state below. j = bsize - mcontext->offset ; memcpy(accum + mcontext->offset, cipher, j); dbg(DBG_CRYPTO, "incrementalDecrypt: Moved %d bytes; " "%d remaining this run\n", j, length - j); mcontext->remaining -= j; cipher += j; length -= j; mcontext->offset = 0; } // reaching this block indicates we have filled up the accumulator. if (mcontext->state == ONE_BLOCK) { // decrypt the one block: dbg(DBG_CRYPTO, "CBCModeM: incrementalDecrypt. State ONE_BLOCK\n"); if (call BlockCipher.decrypt (&context->cc, accum, plain) != SUCCESS) { return FAIL; } // and xor with E(IV), which is stored in lastCipher. for (i = 0; i < bsize; i++) { plain[i] ^= lastCipher[i]; } dumpBuffer ("plain", plain, 8); // and fill in some stats and exit. *done = mcontext->completed = bsize; return SUCCESS; } if (mcontext->state == GENERAL) { // we're in block i, where 0 <= i <= n-2 dbg(DBG_CRYPTO, "CBCModeM: incrementalDecrypt. State GENERAL\n"); // decrypt if (call BlockCipher.decrypt (&context->cc, accum, plain + completed) != SUCCESS) { dbg(DBG_CRYPTO,"Fail 3\n"); return FAIL; } // xor with the prev ciphertext for (i = 0; i < bsize; i++) { plain[i + completed] ^= lastCipher[i]; } // update state: completed += bsize; mcontext->accum = !mcontext->accum; // transition if there are only 2 blocks to go. if (mcontext->remaining <= bsize * 2) { mcontext->state = TWO_LEFT_A; continue; } } if (mcontext->state == TWO_LEFT_A) { // two blocks to go, one after this stage completes. // we have now accumulated C_n dbg(DBG_CRYPTO, "CBCModeM: incrementalDecrypt. State 2LEFTA\n"); // decrypt. note we decrypt INTO the accumulator, which now holds // C_{n-1}/+L ^ P_n || C_{n-1}/-L // we need to wait to receive C_{n-1}/+L to recover P_n as well // as C_{n-1}, which we'll then use to recover P_{n-1} if (call BlockCipher.decrypt (&context->cc, accum, accum) != SUCCESS) { dbg(DBG_CRYPTO,"Fail 4\n"); return FAIL; } // transition state: mcontext->state = TWO_LEFT_B; dbg(DBG_CRYPTO, "DBCModeM: ** Switched to state 2LEFTB " "with %d remaining\n", mcontext->remaining); continue; } if (mcontext->state == TWO_LEFT_B) { // last block. this can't use the accum population code from // above since it's a bit convoluted. recall from TWO_LEFT_A, that // accum contains C_{n-1}/+L ^ P_n || C_{n-1}/-L // cipher contains C_{n-1}+L // dbg(DBG_CRYPTO, "CBCModeM: incrementalDecrypt. State 2LEFTB\n"); j = mcontext->offset + length; // stop pos // iterate over each block of cipher for (i = mcontext->offset; i < j; i++) { dbg(DBG_CRYPTO, "incrementalDecrypt: %d %d\n", i, j); // recover P_n plain[completed + bsize + i] = accum[i] ^ cipher[i-mcontext->offset]; // and set up accum to be C_{n-1} accum[i] = cipher[i-mcontext->offset]; } mcontext->remaining -= length; if (mcontext->remaining) { mcontext->offset += length; length =0; } else { // if we've received all of C_{n-1}, decrypt it, which is // P_{n-1} ^ C_{n-2}; C{n-2} conveniently lives in lastCipher, // so we can xor to recover. if (call BlockCipher.decrypt (&context->cc, accum, plain + completed) != SUCCESS) { dbg(DBG_CRYPTO,"Fail 5\n"); return FAIL; } for (i = 0; i < bsize; i++) { plain[i + completed] ^= lastCipher[i]; } // set some state. mcontext->remaining = 0; mcontext->completed += bsize + length + mcontext->offset; *done = mcontext->completed; return SUCCESS; } } } // and voilla! we're done. *done = mcontext->completed = completed; return SUCCESS; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -