主要差异如下:

1、  对于待加密解密的数据,各自的填充模式不一样

      C#的模式有:ANSIX923、ISO10126、None、PKCS7、Zero,而Java有:NoPadding、PKCS5Padding、SSL3Padding

2、  各自默认的3DES实现,模式和填充方式不一样

C#的默认模式为CBC,默认填充方式为PKCS7; java的默认模式为ECB,默认填充方式为PKCS5Padding

3、  各自的key的size不一样

C#中key的size为16和24均可;java中要求key的size必须为24;对于CBC模式下的向量iv的size两者均要求必须为8

 

翻看了3DES的原理:

DES主要采用替换和移位的方法,用56位密钥对64位二进制数据块进行加密,每次加密可对64位的输入数据进行16轮编码,

经一系列替换和移位后,输入的64位转换成安全不同的64的输出数据

.   
3DES:是在DES的基础上采用三重DES,即用两个56位的密钥K1,K2,发送方用K1加密,K2解密,再使用K1加密.接收方使用K1解密,K2加密,再使用K1解密,

其效果相当于密钥长度加倍.

 

于是尝试在java中,对key进行补位,即用前8个字节作为byte[24] 中的byte[16]~byte[23];发现与c#中加密的结果相同!于是大胆假设C#中可能是检查key的size为16的时候

自动将前8个字节作为k3进行了补位,而java没有实现这一点(因为java的3DES算法中强制要求key的size必须为24)。这样的情况下,可能就是发送方用k1加密、k2解密、k3再加密;接受方k3解密、k2加密、再k1解密来实现。

 

最终经过编码验证,确认key大小为24时,java和c#的加密解密结果相一致。

Java中实现时,只要注意对大小不足24的key进行补位,和采用CBC模式,填充模式为PKCS5Padding即可。


 CDES {

    public static byte[] encrypt(String sKey, byte[] bIV, byte[] bPlainText, int nOffset, int nSize)
            
throws Exception {
        
byte[] bKey = buildKey(sKey);
        
byte[] bInput = buildInput(nSize, bPlainText, nOffset);
        
byte[] bResult = encrypt(bIV, bKey, bInput);
        
return bResult;
    }

    
public static byte[] decrypt(String sKey, byte[] bIV, byte[] bCipherText)
            
throws Exception {
        
byte[] bKey = buildKey(sKey);
        SecretKey securekey 
= buildSecretKey(bKey);
        IvParameterSpec iv 
= new IvParameterSpec(bIV);
        Cipher cipher 
= Cipher.getInstance("DESede/CBC/PKCS5Padding");
        SecureRandom sr 
= new SecureRandom();
        cipher.init(Cipher.DECRYPT_MODE, securekey, iv, sr);
        
byte[] bOutput = cipher.doFinal(bCipherText);
        
int nLen = 0;
        nLen 
= nLen | (int) bOutput[0];
        nLen 
= nLen | ((int) bOutput[1<< 8);
        
if (nLen > bOutput.length - 4) {
            
throw new Exception("非法的密文");
        }        
        
byte[] bResult = new byte[bOutput.length  - 4];
        bResult 
= Arrays.copyOfRange(bOutput, 2, bOutput.length - 2);
        
return bResult;
    }

    
private static byte[] md5Digest(String sData) throws NoSuchAlgorithmException {
        MessageDigest md5 
= MessageDigest.getInstance("MD5");
        
byte[] bData = sData.getBytes();
        md5.update(bData, 
0, bData.length);
        
byte[] hash = md5.digest();
        
return hash;
    }

    
private static byte[] buildInput(int nSize, byte[] bPlainText, int nOffset) {
        
byte[] bInput = new byte[nSize + 4];
        
for (int i = 0; i < bPlainText.length; i++) {
            Arrays.fill(bInput, 
2 + i, 2 + i + 1, bPlainText[i]);
        }
        
int usCRC = CCRC16.CalcCrcCheckSum(bPlainText, nOffset, nSize);
        bInput[
0= (byte) (nSize & 0xFF);
        bInput[
1= (byte) (nSize >> 8 & 0xFF);
        bInput[nSize 
+ 2= (byte) (usCRC & 0xFF);
        bInput[nSize 
+ 3= (byte) (usCRC >> 8 & 0xFF);
        
return bInput;
    }

    
private static byte[] buildKey(String sKey) throws NoSuchAlgorithmException {
        
byte[] bTmp = md5Digest(sKey);
        
byte[] bKey = new byte[24];
        System.arraycopy(bTmp,
0,bKey,0,bTmp.length);
        System.arraycopy(bTmp,
0,bKey,16,8);
        
return bKey;
    }

    
private static SecretKey buildSecretKey(byte[] bkey) throws InvalidKeyException,
            InvalidKeySpecException, NoSuchAlgorithmException {
        DESedeKeySpec dks 
= new DESedeKeySpec(bkey);
        SecretKeyFactory keyFactory 
= SecretKeyFactory.getInstance("DESede");
        SecretKey securekey 
= keyFactory.generateSecret(dks);
        
return securekey;
    }

    
private static byte[] encrypt(byte[] biv, byte[] bkey, byte[] input) throws Exception {
        SecretKey securekey 
= buildSecretKey(bkey);
        IvParameterSpec iv 
= new IvParameterSpec(biv);
        Cipher cipher 
= Cipher.getInstance("DESede/CBC/PKCS5Padding");
        SecureRandom sr 
= new SecureRandom();
        cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
        
return cipher.doFinal(input);
    }
}

class CCRC16 {
    
public static int CalcCrcCheckSum(byte[] pBuffer, int nOffset, int nSize) {

        
int[] table = {
            
0x00000xC0C10xC1810x01400xC3010x03C00x02800xC241,
            
0xC6010x06C00x07800xC7410x05000xC5C10xC4810x0440,
            
0xCC010x0CC00x0D800xCD410x0F000xCFC10xCE810x0E40,
            
0x0A000xCAC10xCB810x0B400xC9010x09C00x08800xC841,
            
0xD8010x18C00x19800xD9410x1B000xDBC10xDA810x1A40,
            
0x1E000xDEC10xDF810x1F400xDD010x1DC00x1C800xDC41,
            
0x14000xD4C10xD5810x15400xD7010x17C00x16800xD641,
            
0xD2010x12C00x13800xD3410x11000xD1C10xD0810x1040,
            
0xF0010x30C00x31800xF1410x33000xF3C10xF2810x3240,
            
0x36000xF6C10xF7810x37400xF5010x35C00x34800xF441,
            
0x3C000xFCC10xFD810x3D400xFF010x3FC00x3E800xFE41,
            
0xFA010x3AC00x3B800xFB410x39000xF9C10xF8810x3840,
            
0x28000xE8C10xE9810x29400xEB010x2BC00x2A800xEA41,
            
0xEE010x2EC00x2F800xEF410x2D000xEDC10xEC810x2C40,
            
0xE4010x24C00x25800xE5410x27000xE7C10xE6810x2640,
            
0x22000xE2C10xE3810x23400xE1010x21C00x20800xE041,
            
0xA0010x60C00x61800xA1410x63000xA3C10xA2810x6240,
            
0x66000xA6C10xA7810x67400xA5010x65C00x64800xA441,
            
0x6C000xACC10xAD810x6D400xAF010x6FC00x6E800xAE41,
            
0xAA010x6AC00x6B800xAB410x69000xA9C10xA8810x6840,
            
0x78000xB8C10xB9810x79400xBB010x7BC00x7A800xBA41,
            
0xBE010x7EC00x7F800xBF410x7D000xBDC10xBC810x7C40,
            
0xB4010x74C00x75800xB5410x77000xB7C10xB6810x7640,
            
0x72000xB2C10xB3810x73400xB1010x71C00x70800xB041,
            
0x50000x90C10x91810x51400x93010x53C00x52800x9241,
            
0x96010x56C00x57800x97410x55000x95C10x94810x5440,
            
0x9C010x5CC00x5D800x9D410x5F000x9FC10x9E810x5E40,
            
0x5A000x9AC10x9B810x5B400x99010x59C00x58800x9841,
            
0x88010x48C00x49800x89410x4B000x8BC10x8A810x4A40,
            
0x4E000x8EC10x8F810x4F400x8D010x4DC00x4C800x8C41,
            
0x44000x84C10x85810x45400x87010x47C00x46800x8641,
            
0x82010x42C00x43800x83410x41000x81C10x80810x4040,};


        
byte[] bytes = pBuffer;
        
int crc = 0x0000;
        
for (byte b : bytes) {
            crc 
= (crc >>> 8^ table[(crc ^ b) & 0xff];
        }

        
return crc;
    }

还有一种让Java和.Net兼容的方式,在.Net中指定模式为ECB,填充为PKCS7,然后在Java中采用其默认的模式(DESede/ECB/PKCS5Padding)即可,注意双方约定key的size为24个字节。建议双方对key以base64编码字符串进行告知,因为java和.net中byte字节的范围不相同(前者-128~127,后者0~255),避免不必要的处理。


参考引用:http://gaoge2000.blog.hexun.com/18731819_d.html


相关文章: