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 個字節,如果不夠,補 '\0',例如:unsigned char key[ ] = { "key\0\0\0\0\0" },如果超過八個字節,那么后面的不使用;如果你不願意補零,那么需要保證和 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個字節,那么補充的字節全部補充為'\0x28',如果分組的大小是 8 個字節,那么 PKCS#7 的填充方式和 PKCS#5 是完全一致的;另外還有一個規定,就是如果明文剛剛好進行分組,那么需要補充一個獨立的分組出來,例如 DES ,如果明文為 8 個字節,那么需要補充為 16 個字節進行運算,這樣的好處是進行解密后,將解密出來的最后一個字節取出來,並將解密結果的長度減去該值,就是原來明文的長度;

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM