我必须解密在java服务器中加密的数据。 在使用triple des的java服务器加密文本中(模式:CFB8,填充:NoPadding) 对于解密,我尝试加密如java服务器 下面是发布的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?
答案 0 :(得分:0)
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。