【问题标题】:How to implement CFB8 mode with Triple DES for decryption using CryptoJS如何使用 CryptoJS 实现具有三重 DES 的 CFB8 模式进行解密
【发布时间】:2015-02-20 07:21:20
【问题描述】:

我必须解密在 java 服务器中加密的数据。 在使用三重des(模式:CFB8,填充:NoPadding)的java服务器加密文本中 对于解密,我尝试过加密,例如 java server 下面贴出java源代码。

private final static String keyString = "123456789012345678901234";
private final static String ivString = "abcdefgh";


public static String encrypt(String data) throws Exception {


    KeySpec keySpec = new DESedeKeySpec(keyString.getBytes());
    SecretKey key = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
    IvParameterSpec iv = new IvParameterSpec(ivString.getBytes());
    Cipher ecipher = Cipher.getInstance("DESede/CFB8/NoPadding");
    ecipher.init(Cipher.ENCRYPT_MODE, key, iv);

    byte[] valeur = data.getBytes("UTF-8");
    byte[] enc = ecipher.doFinal(valeur);

    return new String(Base64.encode(enc, Base64.DEFAULT), "UTF-8");
}

下面的代码是我的代码。

var key="123456789012345678901234";
var iv = "abcdefgh";   
var iv1 = CryptoJS.enc.Utf8.parse(iv);   
var key1 = CryptoJS.enc.Utf8.parse(key);   
var encrypted = CryptoJS.TripleDES.encrypt("asdfg", key1, { 
    iv:iv1,
    mode:CryptoJS.mode.CFB,
    padding:CryptoJS.pad.NoPadding
});

但我不能得到相同的结果。

当我在 Java 代码中将“CFB8”更改为“CFB”时,我得到了相同的结果。

如何在 CryptoJS 中实现 CFB8?

【问题讨论】:

    标签: javascript java cryptojs cfb-mode


    【解决方案1】:

    CFB 是带有移位寄存器的操作模式。加密和解密发生在与移位寄存器大小相同但小于块大小的段中。

    问题在于 CryptoJS 的 CFB 实现只支持与使用的块密码的块大小完全相同的段大小。这意味着当您使用 AES 时,它将是 128 位的段大小。

    我已经实现了 CFB 的可变段大小版本,它支持所有 2 的幂的段大小,包括 1 位到块大小:

    /**
     * Cipher Feedback block mode with segment size parameter according to
     * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf. 
     * The segment size can be anything from 1 bit up to the block size of the 
     * underlying block cipher.
     * 
     * Current limitation: only segment sizes that divide the block size evenly 
     * are supported.
     */
    CryptoJS.mode.CFBb = (function () {
        var C = CryptoJS;
            CFBb = C.lib.BlockCipherMode.extend(),
            WordArray = C.lib.WordArray;
    
        /**
         * Shifts the array by n bits to the left. Zero bits are added as the 
         * least significant bits. This operation modifies the current array.
         * 
         * @param {WordArray} wordArray WordArray to work on
         * @param {int} n Bits to shift by
         * 
         * @returns the WordArray that was passed in
         */
        var bitshift = function(wordArray, n){
            var carry = 0,
                words = wordArray.words,
                wres,
                skipped = 0,
                carryMask;
            if (n > 0) {
                while(n > 31) {
                    // delete first element:
                    words.splice(0, 1);
    
                    // add `0` word to the back
                    words.push(0);
    
                    n -= 32;
                    skipped++;
                }
                if (n == 0) {
                    // 1. nothing to shift if the shift amount is on a word boundary
                    // 2. This has to be done, because the following algorithm computes 
                    // wrong values only for n==0
                    return carry;
                }
                for(var i = words.length - skipped - 1; i >= 0; i--) {
                    wres = words[i];
                    words[i] <<= n;
                    words[i] |= carry;
                    carry = wres >>> (32 - n);
                }
            } else if (n < 0) {
                while(n < -31) {
                    // insert `0` word to the front:
                    words.splice(0, 0, 0);
    
                    // remove last element:
                    words.length--;
    
                    n += 32;
                    skipped++;
                }
                if (n == 0) {
                    // nothing to shift if the shift amount is on a word boundary
                    return carry;
                }
                n = -n;
                carryMask = (1 << n) - 1;
                for(var i = skipped; i < words.length; i++) {
                    wres = words[i] & carryMask;
                    words[i] >>>= n;
                    words[i] |= carry;
                    carry = wres << (32 - n);
                }
            }
            return carry;
        };
    
        /**
         * Negates all bits in the WordArray. This manipulates the given array.
         * 
         * @param {WordArray} wordArray WordArray to work on
         * 
         * @returns the WordArray that was passed in
         */
        var neg = function(wordArray){
            var words = wordArray.words;
            for(var i = 0; i < words.length; i++) {
                words[i] = ~words[i];
            }
            return wordArray;
        };
    
        CFBb.Encryptor = CFBb.extend({
            processBlock: function(words, offset){
                processBlock.call(this, words, offset, true);
            }
        });
    
        CFBb.Decryptor = CFBb.extend({
            processBlock: function(words, offset){
                processBlock.call(this, words, offset, false);
            }
        });
    
        function processBlock(words, offset, encryptor) {
            // Shortcuts
            var self = this;
            var cipher = self._cipher;
            var blockSize = cipher.blockSize * 32; // in bits
            var prev = self._prevBlock;
            var segmentSize = cipher.cfg.segmentSize; // in bits
            var i, j;
            var currentPosition;
    
            // Create a bit mask that has a comtinuous slice of bits set that is as big as the segment
            var fullSegmentMask = [];
            for(i = 31; i < segmentSize; i += 32) {
                fullSegmentMask.push(0xffffffff);
            }
            // `s` most signiicant bits are set:
            fullSegmentMask.push(((1 << segmentSize) - 1) << (32 - segmentSize));
            for(i = fullSegmentMask.length; i < words.length; i++) {
                fullSegmentMask.push(0);
            }
    
            fullSegmentMask = WordArray.create(fullSegmentMask);
    
            // some helper variables
            var slidingSegmentMask = fullSegmentMask.clone(),
                slidingSegmentMaskShifted = slidingSegmentMask.clone(),
                slidingNegativeSegmentMask,
                prevCT;
    
            // shift the mask according to the current offset
            bitshift(slidingSegmentMaskShifted, -offset * 32);
    
            for(i = 0; i < blockSize/segmentSize; i++) {
                if (!prev) {
                    prev = self._iv.slice(0); // clone
    
                    // Remove IV for subsequent blocks
                    self._iv = undefined;
                } else {
                    // Prepare the iteration by concatenating the unencrypted part of the previous block and the previous ciphertext
    
                    prev = WordArray.create(prev);
                    bitshift(prev, segmentSize);
                    prev = prev.words;
                    previousCiphertextSegment = self._ct;
    
                    // fill previous ciphertext up to the block size
                    while(previousCiphertextSegment.length < blockSize / 32) {
                        previousCiphertextSegment.push(0);
                    }
                    previousCiphertextSegment = WordArray.create(previousCiphertextSegment);
    
                    // move to the back
                    bitshift(previousCiphertextSegment, -blockSize + segmentSize);
    
                    // put together
                    for (var j = 0; j < prev.length; j++) {
                        prev[j] |= previousCiphertextSegment.words[j];
                    }
                }
    
                currentPosition = offset * 32 + i * segmentSize;
    
                // move segment in question to the front of the array
                var plaintextSlice = WordArray.create(words.slice(0));
                bitshift(plaintextSlice, currentPosition);
    
                if (!encryptor) {
                    self._ct = plaintextSlice.words.slice(0, Math.ceil(segmentSize / 32));
                }
    
                var segKey = prev.slice(0); // clone
                cipher.encryptBlock(segKey, 0);
    
                // Encrypt segment
                for (j = 0; j < Math.ceil(segmentSize / 32); j++) {
                    plaintextSlice.words[j] ^= segKey[j];
                }
    
                // Filter only the current segment
                for (j = 0; j < plaintextSlice.words.length; j++) {
                    plaintextSlice.words[j] &= fullSegmentMask.words[j];
                }
    
                if (encryptor) {
                    self._ct = plaintextSlice.words.slice(0, Math.ceil(segmentSize / 32));
                }
    
                // remove the segment from the plaintext array
                slidingNegativeSegmentMask = neg(slidingSegmentMaskShifted.clone());
                for (j = 0; j < words.length; j++) {
                    words[j] &= slidingNegativeSegmentMask.words[j];
                }
    
                // move filtered ciphertext segment to back to the correct place
                bitshift(plaintextSlice, -currentPosition);
    
                // add filtered ciphertext segment to the plaintext/ciphertext array
                for (j = 0; j < words.length; j++) {
                    words[j] |= plaintextSlice.words[j];
                }
    
                // shift the segment mask further along
                bitshift(slidingSegmentMask, -segmentSize);
                bitshift(slidingSegmentMaskShifted, -segmentSize);
            }
            self._prevBlock = prev;
        }
    
        return CFBb;
    }());
    

    您应该使用适当的填充。 CryptoJS 默认使用 PKCS#7 填充。 CFB8 的最佳填充是完全没有填充(您已经使用过)。

    例子:

    var iv = CryptoJS.lib.WordArray.random(128/8);
    var encrypted = CryptoJS.TripleDES.encrypt("message", key, {
        iv: iv, 
        mode: CryptoJS.mode.CFBb, 
        padding: CryptoJS.pad.NoPadding,
        segmentSize: 8
    });
    var recoveredPlaintext = CryptoJS.TripleDES.decrypt(encrypted, key, {
        iv: iv,
        mode: CryptoJS.mode.CFBb,
        padding: CryptoJS.pad.NoPadding,
        segmentSize: 8
    });
    console.log(recoveredPlaintext.toString(CryptoJS.enc.Utf8));
    

    由于这是使用随机 IV,因此查看 Java 和 JavaScript 实现是否兼容的唯一方法是在一个方向上加密并在另一个方向上解密。

    请记住,由于 IV 是随机的,因此您需要将其与密文一起发送。由于不需要保密,因此您可以轻松地将其添加到密文中,并在解密之前将其切掉。

    此代码是我在 GitHub 上的存储库的自定义副本:artjomb/cryptojs-extension

    【讨论】:

      猜你喜欢
      • 2019-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多