zoukankan      html  css  js  c++  java
  • DES 算法的 C++ 与 JAVA 互相加解密

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html
    内部邀请码:C8E245J (不写邀请码,没有现金送)
    国内私募机构九鼎控股打造,九鼎投资是在全国股份转让系统挂牌的公众公司,股票代码为430719,为“中国PE第一股”,市值超1000亿元。 
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    在 JAVA 中,从 J2EE1.4 开始,SUN 提供了 JCE( JAVA CRYPTO ENGINE ),其中包含有 DES 算法,在 JAVA 中使用 DES 算法的代码示例如下:

    import java.security.Key;
    import java.security.Security;
    import javax.crypto.Cipher;
    
    public class DESPlus
    {
     static String strDefaultKey = "initkey";
     static Cipher encryptCipher = null;
     static Cipher decryptCipher = null;
     
     static {
         Security.addProvider(new com.sun.crypto.provider.SunJCE());
         Key key = null;
        try {
          key = getKey(strDefaultKey.getBytes());
          encryptCipher = Cipher.getInstance("DES");
          encryptCipher.init(Cipher.ENCRYPT_MODE, key);
    
          decryptCipher = Cipher.getInstance("DES");
          decryptCipher.init(Cipher.DECRYPT_MODE, key);
        }catch(Exception e){
            e.printStackTrace();
            }
        }
    
     public DESPlus(){
     }
    
     public static byte[] encrypt(byte[] arrB) throws Exception {
      return encryptCipher.doFinal(arrB);
     }
    
     public static byte[] decrypt(byte[] arrB) throws Exception {
      return decryptCipher.doFinal(arrB);
     }
    
     private static  Key getKey(byte[] arrBTmp) throws Exception {
      byte[] arrB = new byte[8];
      for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
       arrB[i] = arrBTmp[i];
      }
      Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES");
      return key;
     }
     
    }

    需要注意的是,加密后的结果是字节数组,一般情况下可以使用 BASE64 进行编码,以方便存储在字符串形的数据库字段中,当然亦可以采用原始的字节流或者是十六进制编码字符串;同样需要注意的是,在上面的代码示例中,JAVA 的 DES 算法可以指定加密的模式和填充方式,如果不指定,则默认的就是 ECB 加密模式和 PKCS#5 填充方式,关于加密模式和填充方式之后将进行介绍,现在我们来看 OPENSLL 的 DES 算法,还是先给一段代码示例:

    int Encrypt( unsigned char * inbuf , unsigned char * * outbuf , int inlen , unsigned char * key, unsigned char * iv )
    {
        BIO *bio, *mbio, *cbio;
        unsigned char *dst;
        int outlen;
    
        mbio = BIO_new( BIO_s_mem( ) );
        cbio = BIO_new( BIO_f_cipher( ) );
        BIO_set_cipher( cbio , EVP_des_ecb( ) , key , iv , 1 );
    
        bio = BIO_push( cbio , mbio );
        BIO_write( bio , inbuf , inlen );
        BIO_flush( bio );
    
        outlen = BIO_get_mem_data( mbio , (unsigned char **) & dst );
        * outbuf = ( unsigned char * ) malloc( outlen );
        memcpy( * outbuf , dst , outlen );
        BIO_free_all( bio );
    
        return outlen;
    }

    该段代码使用了 OPENSSL 库,该函数返回加密结果的长度,同时将加密的结果放置在 outbuf 中,需要注意的是,BIO_set_chiper 这一行,最后两个参数:iv 参数在 ECB 加密模式下是不起作用的,仅 CBC 模式才会使用该变量,该变量要求必须是一个八字节的数组,enc 参数,如果是 1 则表明是进行加密,如果是 0 则表明是解密,-1 则表明使用最后一次操作的方式,只需要修改最后一个参数为0,就是解密了,所以解密的代码就不再重复了;

    另外补充一点,这个加密方式是最古老的 DES ,不是 3DES ,输入参数 KEY 的长度要求至少是 8 个字节,如果不够,补 '',例如:unsigned char key[ ] = { "key" },如果超过八个字节,那么后面的不使用;如果你不愿意补零,那么需要保证和 JAVA 的对应,否则不能互相加解密;

    哦,还有一点,请注意在使用完后释放 outbuf 内存块,保证没有内存泄露;

    下面来说一下加密模式,常见的加密模式有 ECB / CBC / CFB / OFB 四种,这也是 OPENSSL 提供的四种,加密模式的主要意义就是,加密算法是按块进行加密的,例如 DES ,是 64Bit 一个块的进行加密,就是每次加密 8 个字节,因此每次输入八个字节的明文输出八个字节密文,如果是 16 个字节,那么分成两个块依次进行加密,问题就出现在这里,如果明文是 1234567812345678,分块分别进行加密,那么加密的结果类似“C4132737962C519C C4132737962C519C”,可以看出明文的规律,这就是 ECB 加密模式,密文可以看出明文的规律;为了解决这个问题,有了其他的加密模式:CBC 加密模式(密码分组连接),CFB加密模式(密码反馈模式),OFB加密模式(输出反馈模式)CBC 是要求给一个初始化的向量,然后将每个输出与该向量作运算,并将运算的结果作为下一个加密块的初始化向量,CFB 和 OFB 则不需要提供初始化向量,直接将密码或者输出作为初始化向量进行运算;这样就避免了明文的规律出现在密文中;当然缺点是解密时需要保证密文的正确性,如果网络传输时发生了一部分错误,则后面的解密结果就可能是错误的;(ECB模式仅影响传输错误的那个块);

    密码算法基本上都是分组(按快)进行加密的,如果密文长度不是刚刚好可以进行分组,怎么办?只能进行填充,填充的方法有很多中,常用的是 PKCS#7,该填充方法是将每一个补充的字节内容填充为填充的字节个数;例如明文长度是 100 , 分组的大小是32个字节,那么需要分为四组,补充28个字节,那么补充的字节全部补充为'x28',如果分组的大小是 8 个字节,那么 PKCS#7 的填充方式和 PKCS#5 是完全一致的;另外还有一个规定,就是如果明文刚刚好进行分组,那么需要补充一个独立的分组出来,例如 DES ,如果明文为 8 个字节,那么需要补充为 16 个字节进行运算,这样的好处是进行解密后,将解密出来的最后一个字节取出来,并将解密结果的长度减去该值,就是原来明文的长度;

    更多的信息可以参考:http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation

  • 相关阅读:
    宏定义问题
    (转载)(int)a、&a、(int)&a、(int&)a的区别,很偏僻的题
    boolalpha的作用
    一些小细节
    HTTP Keep-Alive的作用
    数据库三大范式
    laravel 安装语言包
    MySQL存储引擎中的MyISAM和InnoDB区别详解
    推荐一款超好用的工具cmder
    如何保证代码质量
  • 原文地址:https://www.cnblogs.com/AloneSword/p/3479376.html
Copyright © 2011-2022 走看看