zoukankan      html  css  js  c++  java
  • 数据加密与平台无关性示例

    在计算机软件开发世界中,编程语言种类极多,数据在各种语言的表现形式可能有所差异,但数据本身的处理可能,或者说本质上是完全一样的;比如数据在某个算法中的运算过程是一样的。在这里,我以加密与解密来作为例子说明。

           在C++下,我使用OPENSSL库生成了RSA的公私钥对与DES加密之用的会话密钥,并将这三者及加密结果写入文件以备在Java环境下使用。

         在C++程序中,我使用使用公钥来加密了DES的会话密钥,然后在Java下使用私钥来解密会话密钥;在运算结果中,我未做其它方面的码制转换,即按密钥的初始格式DER编码,数学运算结果也是按DER编码来实现。

      在Java程序中,我从之前所存储的几个文件中取得密钥与加密结果来做解密。我使用了BC的JCE,即bcprov-jdk14-119.jar,在使用之前,需要先安装此JCE:

    假设JDK:jdk1.4\jre\
    把BC包放到JRE下的ext:jdk1.4\jre\lib\ext
    修改文件jdk1.4\jre\lib\security\java.security:
    #
    # List of providers and their preference orders (see above):
    #
    security.provider.1=sun.security.provider.Sun
    security.provider.2=com.sun.net.ssl.internal.ssl.Provider
    security.provider.3=com.sun.rsajca.Provider
    security.provider.4=com.sun.crypto.provider.SunJCE
    security.provider.5=sun.security.jgss.SunProvider

    security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider

    ======================================================================

    C++程序源码:

    #include
    #include
    #include
    //#define _RSA_KEY_PAIR_GENERATE_//密钥是否要生成 只需要在第一次运行时打开此宏

    #define _RSA_KEY_PAIR_TOFILE_//密钥对是否要写入文件

    #define  MAX_RSA_KEY_LENGTH 512 //密钥的最大长度是512字节

    #define PUBKEY_ENCRYPT
    #define PRIKEY_DECRYPT

    #pragma  comment(lib, "../lib/libeay32.lib")
    static const char * PUBLIC_KEY_FILE = "pubkey.key";
    static const char * PRIVATE_KEY_FILE = "prikey.key";

    int RsaKeyPairGen(void)
    {
     RSA *rsa = NULL;

    #ifdef _RSA_KEY_PAIR_GENERATE_
     //生成RSA密钥对:
     rsa = RSA_new();
     rsa = RSA_generate_key(1024, 0x10001, NULL, NULL);
    #endif
     
     //把密钥对写入文件,以后从文件里读取
    #ifdef _RSA_KEY_PAIR_TOFILE_
     unsigned char ucPubKey[MAX_RSA_KEY_LENGTH] = {0}, ucPriKey[MAX_RSA_KEY_LENGTH] = {0};
     int len = i2d_RSAPublicKey(rsa,NULL);
     unsigned char* pt = ucPubKey;
     len = i2d_RSAPublicKey(rsa, &pt);
     
     FILE *fpubkey = NULL;
     fpubkey = fopen(PUBLIC_KEY_FILE, "wb");
     if(fpubkey == NULL)
     {
      cout << "fopen pubkey.key failed!" << endl;
      return 0x01;
     }
     fwrite(ucPubKey, 1, len, fpubkey);
     fclose(fpubkey);
     
     len = i2d_RSAPrivateKey(rsa,NULL);
     unsigned char* pt2 = ucPriKey;
     len = i2d_RSAPrivateKey(rsa,&pt2);
     FILE *fprikey = NULL;
     fprikey = fopen(PRIVATE_KEY_FILE, "wb");
     if(fprikey == NULL)
     {
      cout << "fopen prikey.key failed!" << endl;
      return 0x02;
     }
     fwrite(ucPriKey, 1, len, fprikey);
     fclose(fprikey);
    #endif
     
     if(rsa != NULL)
     {
      RSA_free(rsa);
      rsa = NULL;
     }
     return 0;
    }

    //从文件里读取私钥的数据,取得RSA格式的私钥:
    int GetPriKey(unsigned char *pucPriKeyData, unsigned long KeyDataLen, RSA* *priRsa)
    {
     unsigned char *Pt = pucPriKeyData;
     *priRsa = d2i_RSAPrivateKey(NULL, &Pt, KeyDataLen);
     if(priRsa == NULL)
     {
      cout << "priRsa == NULL!" << endl;
      return 0x22;
     }
     return 0;
    }

    //取得RSA格式的公钥:
    int GetPubKey(unsigned char *pucPubKeyData,unsigned long KeyDataLen, RSA* *pubRsa)
    {
     unsigned char *Pt = pucPubKeyData;
     *pubRsa = d2i_RSAPublicKey(NULL, &Pt, KeyDataLen);
     if(pubRsa == NULL)
     {
      cout << "pubRsa == NULL!" << endl;
      return 0x31;
     }
     return 0;
    }

    //公钥加密会话密钥:
    int encSessionKeybyRsaPubKey(RSA *rsa, unsigned char *ucKey, unsigned long ulKeyLen,
            unsigned char *outData, unsigned long *pulOutLen)
    {
     return (*pulOutLen = RSA_public_encrypt(ulKeyLen, ucKey, outData, rsa, 1));
    }

    //私钥解密会话密钥:
    int decSessionKeybyRsaPriKey(RSA *rsa, unsigned char *InData, unsigned long ulDataLen,
            unsigned char *ucKey, unsigned long *pulKeyLen)
    {
     return (*pulKeyLen = RSA_private_decrypt(ulDataLen, InData, ucKey, rsa, 1));
    }


    int main(int argc, char* argv[])
    {
     unsigned char ucKey[8] = {0x01, 0x03, 0x99, 0x4, \
      0x80, 0x65, 0x34, 0x08};
     unsigned char ucEncryptedKey[512] = {0}, ucDecryptedKey[512] = {0};
     unsigned long encrypted_len = 0, decrypted_len = 0;
     
     
    #ifdef  _RSA_KEY_PAIR_GENERATE_
     RsaKeyPairGen();
    #endif

     //取得公钥:
     unsigned char ucPubKey[MAX_RSA_KEY_LENGTH] = {0};
     
     FILE *fpubkey = NULL;
     fpubkey = fopen(PUBLIC_KEY_FILE, "rb");
     if(fpubkey == NULL)
     {
      cout << "fopen pubkey.key failed!" << endl;
      return 0x03;
     }
     fseek(fpubkey, 0, SEEK_END);
     int len_PK = ftell(fpubkey);
     fseek(fpubkey, 0, SEEK_SET);
     fread(ucPubKey, 1, len_PK, fpubkey);
     fclose(fpubkey);

    #ifdef  PUBKEY_ENCRYPT
     RSA *pRsaPubKey = NULL;
     pRsaPubKey = RSA_new();
     
     GetPubKey(ucPubKey, len_PK, &pRsaPubKey);
     //公钥加密:
     encSessionKeybyRsaPubKey(pRsaPubKey, ucKey, sizeof(ucKey), ucEncryptedKey, &encrypted_len);
     //write to file:
     FILE *fp = NULL;
     fp = fopen("ucKey.data", "wb");
     fwrite(ucEncryptedKey, 1, encrypted_len, fp);
     fclose(fp);

     if(pRsaPubKey != NULL)
     {
      RSA_free(pRsaPubKey); pRsaPubKey = NULL;
     }
    #endif
     
     //取得私钥:
     unsigned char ucPriKey[MAX_RSA_KEY_LENGTH] = {0};
     
     FILE *fprikey = NULL;
     fprikey = fopen(PRIVATE_KEY_FILE, "rb");
     if(fprikey == NULL)
     {
      cout << "fopen prikey.key failed!" << endl;
      return 0x02;
     }
     fseek(fprikey, 0, SEEK_END);
     int len_SK = ftell(fprikey);
     fseek(fprikey, 0, SEEK_SET);
     fread(ucPriKey, 1, len_SK, fprikey);
     fclose(fprikey);

    #ifdef PRIKEY_DECRYPT
     RSA *pRsaPriKey = NULL;
     pRsaPriKey = RSA_new();
     
     GetPriKey(ucPriKey, len_SK, &pRsaPriKey);
     //私钥解密:
     FILE *fp1 = NULL;
     fp1 = fopen("ucKey.data", "rb");
     int len = ftell(fp1);
     fseek(fp1, 0, SEEK_SET);
     fread(ucPriKey, 1, len_SK, fp1);
     fclose(fp1);
     decSessionKeybyRsaPriKey(pRsaPriKey, ucEncryptedKey, encrypted_len, ucDecryptedKey, &decrypted_len);
     if(pRsaPriKey != NULL)
     {
      RSA_free(pRsaPriKey); pRsaPriKey = NULL;
     }

     //数据对比:
     if(0 == memcmp(ucKey, ucDecryptedKey, decrypted_len))
     {
      cout << "OK!" << endl;
     }
     else
     {
      cout << "FAILED!" << endl;
     }
    #endif
     
     return 0;
    }

    ======================================================================

    Java程序源码:

    ======================================================================

    package jrsaencrypt;

    import java.io.*;
    import java.security.*;
    import java.security.spec.*;
    import java.security.PublicKey;
    import java.security.PrivateKey;
    import java.security.KeyFactory;
    import javax.crypto.Cipher.*;

    /**
     *

    Title:


     *

    Description:


     *

    Copyright: Copyright (c) 2005


     *

    Company:


     * @author not attributable
     * @version 1.0
     */

    public class RsaKeyGen {

      public RsaKeyGen() {
      }
      /**
       * 生成RSA密钥对
       * @return
       */
      int generateRsaKeyPair() {
        //generate an RSA key pair
        try {
          KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
          keyGen.initialize(1024);
          KeyPair pair = keyGen.generateKeyPair();
          System.out.println(pair.getPublic().getFormat());
          System.out.println(pair.getPublic().getAlgorithm());
          System.out.println("\nRSA public Key:");
          byte[] bPubKey = pair.getPublic().getEncoded();
          System.out.println(bPubKey.length);
          for (int i = 0; i < bPubKey.length; i++) {
            System.out.print(bPubKey[i] + " ");
          }
          System.out.println("\nRSA private Key:");
          byte[] bPriKey = pair.getPrivate().getEncoded();
          System.out.println(bPriKey.length);
          for (int i = 0; i < bPriKey.length; i++) {
            System.out.print(bPriKey[i] + " ");
          }

        }
        catch (Exception e) {
          e.printStackTrace();
        }
        return 0;
      }
      /**
       * 从公钥数据取得公钥
       * @param bPubKeyInput
       * @return
       */
      PublicKey getRsaPubKey(byte[] bPubKeyInput) {
        byte[] bX509PubKeyHeader = {
            48, -127, -97, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0,
            3, -127, -115, 0};
        try {
          byte[] bPubKey = new byte[bPubKeyInput.length + bX509PubKeyHeader.length];
          System.arraycopy(bX509PubKeyHeader, 0, bPubKey, 0,
                           bX509PubKeyHeader.length);
          System.arraycopy(bPubKeyInput, 0, bPubKey, bX509PubKeyHeader.length,
                           bPubKeyInput.length);

          X509EncodedKeySpec rsaKeySpec = new X509EncodedKeySpec(bPubKey);
          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
          rsaPubKey = keyFactory.generatePublic(rsaKeySpec);
        }
        catch (Exception e) {
          e.printStackTrace();
        }

        return rsaPubKey;
      }

      /**
       * 从私钥数据取得私钥
       * @param bPriKeyInput
       * @return
       */
      PrivateKey getRsaPriKey(byte[] bPriKeyInput) {
        byte[] bX509PriKeyHeader = {
            48, -126, 2, 117, 2, 1, 0, 48, 13, 6, 9, 42,
            -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 4, -126, 2, 95};
        try {
          byte[] bPriKey = new byte[bX509PriKeyHeader.length + bPriKeyInput.length];
          System.arraycopy(bX509PriKeyHeader, 0, bPriKey, 0,
                           bX509PriKeyHeader.length);
          System.arraycopy(bPriKeyInput, 0, bPriKey, bX509PriKeyHeader.length,
                           bPriKeyInput.length);

          PKCS8EncodedKeySpec rsaKeySpec = new PKCS8EncodedKeySpec(bPriKey);
          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
          rsaPriKey = keyFactory.generatePrivate(rsaKeySpec);
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        return rsaPriKey;
      }

      /**
       * 从文件里取得数据
       * @param strFileName
       * @param bFBytes
       * @return
       */
      int getBytesbyFileName(String strFileName, byte[] bFBytes) {
        int fSize = 0;
        try {
          FileInputStream fIn = new FileInputStream(strFileName);
          fSize = fIn.available();
          System.out.print("file's size: ");
          System.out.println(fSize);
          fSize = fIn.read(bFBytes);
          fIn.close();
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        return fSize;
      }

      /**
       * 公钥加密
       * @param bKey
       * @return
       */
      byte[] rsaPubKeyEncrypt(byte[] bKey) {
        try {
    //      Provider prvd = Security.getProvider("BouncyCastle");
          javax.crypto.Cipher rsaPKenc = javax.crypto.Cipher.getInstance(
              "RSA/ECB/PKCS1Padding");
          rsaPKenc.init(javax.crypto.Cipher.ENCRYPT_MODE, rsaPubKey);
          bEncryptedData = rsaPKenc.doFinal(bKey);
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        return bEncryptedData;
      }

      /**
       * 私钥解密
       * @param bEncryptedKey
       * @return
       */
      byte[] rsaPriKeyDecrypt(byte[] bEncryptedKey) {
        try {
          javax.crypto.Cipher rsaSKDec = javax.crypto.Cipher.getInstance(
              "RSA/ECB/PKCS1Padding");
          rsaSKDec.init(javax.crypto.Cipher.DECRYPT_MODE, rsaPriKey);
          byte[] bDecrypt = rsaSKDec.doFinal(bEncryptedKey);
    //      System.out.println("rsa decrypted result[before clean]:");
    //      for (int i = 0; i < bDecrypt.length; i++) {
    //        System.out.print(bDecrypt[i] + " ");
    //      }
    //      System.out.println();

          int i = 0;
    //      for (i = bDecrypt.length; i > 1; i--) {
    //        if (bDecrypt[i-1] == 0) {
    //          System.out.println("i=" + i);
    //          break;
    //        }
    //      } //for
          bDecryptedData = new byte[bDecrypt.length - i];
          System.arraycopy(bDecrypt, i, bDecryptedData, 0, bDecrypt.length - i);
        }
        catch (Exception e) {
          e.printStackTrace();
        }
        return bDecryptedData;
      }

      public static void main(String[] args) {
        RsaKeyGen rsaKeyGen1 = new RsaKeyGen();

    //    rsaKeyGen1.generateRsaKeyPair();

    //    byte[] bPubKey = new byte[140];
    //    int len = rsaKeyGen1.getBytesbyFileName("pubkey.key", bPubKey);
    //    rsaKeyGen1.getRsaPubKey(bPubKey);

        byte[] bPriKey = new byte[607];
        int len2 = rsaKeyGen1.getBytesbyFileName("prikey.key", bPriKey);
        rsaKeyGen1.getRsaPriKey(bPriKey);
    //    byte[] bKey = {
    //        1, 2, 3, 4, 5, 6, 7, 8};
    //    //encrypt:
    //    byte[] bEncKey = rsaKeyGen1.rsaPubKeyEncrypt(bKey);
    //    System.out.println("rsa encrypted result:");
    //    for (int i = 0; i < bEncKey.length; i++) {
    //      System.out.print(bEncKey[i] + " ");
    //    }
    //    System.out.println();

        byte[] bEncKey = new byte[128];
        int len0 = rsaKeyGen1.getBytesbyFileName("ucKey.data", bEncKey);
        byte[] bDecKey = rsaKeyGen1.rsaPriKeyDecrypt(bEncKey);
        System.out.println("rsa decrypted result:");
        for (int i = 0; i < bDecKey.length; i++) {
          System.out.print(bDecKey[i] + " ");
        }
        System.out.println();
      }

      PublicKey rsaPubKey;
      PrivateKey rsaPriKey;
      byte[] bEncryptedData;
      byte[] bDecryptedData;
    }

    ======================================================================

    在这里,我简单地写加密与解密的一小部分。在更多的场合中,或者在各种不同的算法里,只需要在各种不同的语言环境里,给算法指定好相同的加密模式与补齐方式,保证字节序列相同,密钥的生成方式与编码相同,那么,无论哪种开发语言,对数据的处理结果应当就是一样的。

    而对于不同的硬件平台来说,则有可能存在一定的差异,这一点需要注意了,因为,我曾经碰到了这样的一个问题,若对字节入栈不一样的话,某种加密算法的结果则有所差异,这个BUG很难查出来,只因为差了一个字节,即有可能是CPU对字节的得理不一样,希望这个难题别让您给遇上了!

    以上二部分源码分别在VC6与JB9测试通过。

  • 相关阅读:
    URAL 2067 Friends and Berries (推理,数学)
    URAL 2070 Interesting Numbers (找规律)
    URAL 2073 Log Files (模拟)
    URAL 2069 Hard Rock (最短路)
    URAL 2068 Game of Nuts (博弈)
    URAL 2066 Simple Expression (水题,暴力)
    URAL 2065 Different Sums (找规律)
    UVa 1640 The Counting Problem (数学,区间计数)
    UVa 1630 Folding (区间DP)
    UVa 1629 Cake slicing (记忆化搜索)
  • 原文地址:https://www.cnblogs.com/adylee/p/1113631.html
Copyright © 2011-2022 走看看