首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用三重DES实现CFB8模式的CryptoJS解密

如何用三重DES实现CFB8模式的CryptoJS解密
EN

Stack Overflow用户
提问于 2014-12-22 07:43:34
回答 1查看 1.1K关注 0票数 0

我必须解密在java服务器中加密的数据。在使用三重des(模式:CFB8 8,填充:NoPadding)进行解密的java服务器加密文本中,我尝试过加密,例如下面的java服务器发布了java源代码。

代码语言:javascript
复制
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");
}

下面的代码是我的代码。

代码语言:javascript
复制
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”时,我得到了相同的结果。

如何在CFB8中实现CryptoJS?

EN

回答 1

Stack Overflow用户

发布于 2015-07-23 08:31:38

循环流化床( CFB )是一种带有换档寄存器的工作方式。加密和解密发生在与移位寄存器大小相同且小于块大小的段中。

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

我已经实现了一个可变段大小的CFB版本,它支持所有的分段大小,这些大小是2的幂,包括1位以下的块大小:

代码语言:javascript
复制
/**
 * 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最好的填充方式是根本不填充(您已经使用过)。

示例:

代码语言:javascript
复制
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上的存储库中的一个自定义副本。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27598524

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档