JAVA加密解密之DH(Diffie-Hellman)算法

DH算法简介

Diffie-Hellman算法(D-H算法),密钥一致协议。是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成”一致”的、可以共享的密钥。换句话说,就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密。这样,在互通了本地密钥(SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!该算法源于中国的同余定理——中国馀数定理。

  1. 甲方构建密钥对儿,将公钥公布给乙方,将私钥保留;双方约定数据加密算法;乙方通过甲方公钥构建密钥对儿,将公钥公布给甲方,将私钥保留。
  2. 甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给乙方加密后的数据;乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。
  3. 乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给甲方加密后的数据;甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。

DH算法实现

package com.jianggujin.codec;

import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;

import com.jianggujin.codec.util.JCipherInputStream;
import com.jianggujin.codec.util.JCipherOutputStream;
import com.jianggujin.codec.util.JCodecException;

/**
 * Diffie-Hellman算法(D-H算法),密钥一致协议。是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。
 * 简单的说就是允许两名用户在公开媒体上交换信息以生成"一致"的、可以共享的密钥。换句话说,就是由甲方产出一对密钥(公钥、私钥),
 * 乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密
 * 。这样,在互通了本地密钥(SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,
 * 同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!
 * 该算法源于中国的同余定理——中国馀数定理
 * <ol>
 * <li>甲方构建密钥对儿,将公钥公布给乙方,将私钥保留;双方约定数据加密算法;乙方通过甲方公钥构建密钥对儿,将公钥公布给甲方,将私钥保留。</li>
 * <li>甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给乙方加密后的数据;乙方使用私钥、甲方公钥、
 * 约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。</li>
 * <li>乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给甲方加密后的数据;甲方使用私钥、乙方公钥、
 * 约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。</li>
 * </ol>
 * 
 * @author jianggujin
 * 
 */
public class JDH {

   private final static String ALGORITHM = "DH";

   /**
    * 对称算法
    * 
    * @author jianggujin
    *
    */
   public static enum JDHSymmetricalAlgorithm {
      DES, DESede;
      public String getName() {
         return this.name();
      }
   }

   /**
    * 初始化甲方密钥
    * 
    * @return
    */
   public static KeyPair initPartyAKey() {
      return initPartyAKey(1024);
   }

   /**
    * 初始化甲方密钥
    * 
    * @param keySize
    * @return
    */
   public static KeyPair initPartyAKey(int keySize) {
      try {
         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(ALGORITHM);
         keyPairGen.initialize(keySize);
         return keyPairGen.generateKeyPair();
      } catch (NoSuchAlgorithmException e) {
         throw new JCodecException(e);
      }
   }

   /**
    * 初始化乙方密钥
    * 
    * @param partyAPublicKey
    *           甲方公钥
    * @return
    */
   public static KeyPair initPartyBKey(byte[] partyAPublicKey) {
      try {
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(partyAPublicKey);
         KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
         PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

         // 由甲方公钥构建乙方密钥
         DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();

         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
         keyPairGenerator.initialize(dhParamSpec);

         return keyPairGenerator.generateKeyPair();
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }

   /**
    * 加密
    * 
    * @param data
    *           加密数据
    * @param privateKey
    *           己方私钥
    * @param publicKey
    *           对方公钥
    * @param algorithm
    *           对称算法
    * @return
    */
   public static byte[] encrypt(byte[] data, byte[] privateKey, byte[] publicKey, String algorithm) {
      // 数据加密
      Cipher cipher = getEncryptCipher(privateKey, publicKey, algorithm);

      try {
         return cipher.doFinal(data);
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }

   /**
    * 包裹输出流,包裹后的输出流为加密输出流
    * 
    * @param out
    * @param privateKey
    * @param publicKey
    * @param algorithm
    * @return
    */
   public static OutputStream wrap(OutputStream out, byte[] privateKey, byte[] publicKey, String algorithm) {
      // 数据加密
      Cipher cipher = getEncryptCipher(privateKey, publicKey, algorithm);

      return new JCipherOutputStream(cipher, out);
   }

   /**
    * 获得加密模式的{@link Cipher}
    * 
    * @param privateKey
    * @param publicKey
    * @param algorithm
    * @return
    */
   public static Cipher getEncryptCipher(byte[] privateKey, byte[] publicKey, String algorithm) {
      return getCipher(privateKey, publicKey, algorithm, Cipher.ENCRYPT_MODE);
   }

   /**
    * 解密
    * 
    * @param data
    *           解密数据
    * @param privateKey
    *           己方私钥
    * @param publicKey
    *           对方公钥
    * @param algorithm
    *           对称算法
    * @return
    */
   public static byte[] decrypt(byte[] data, byte[] privateKey, byte[] publicKey, String algorithm) {
      // 数据解密
      Cipher cipher = getDecryptCipher(privateKey, publicKey, algorithm);
      try {
         return cipher.doFinal(data);
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }

   /**
    * 包裹输入流,原输入流为加密数据输入流
    * 
    * @param in
    * @param privateKey
    * @param publicKey
    * @param algorithm
    * @return
    */
   public static InputStream wrap(InputStream in, byte[] privateKey, byte[] publicKey, String algorithm) {
      // 数据解密
      Cipher cipher = getDecryptCipher(privateKey, publicKey, algorithm);
      return new JCipherInputStream(cipher, in);
   }

   /**
    * 获得解密模式的{@link Cipher}
    * 
    * @param privateKey
    * @param publicKey
    * @param algorithm
    * @return
    */
   public static Cipher getDecryptCipher(byte[] privateKey, byte[] publicKey, String algorithm) {
      return getCipher(privateKey, publicKey, algorithm, Cipher.DECRYPT_MODE);
   }

   private static Cipher getCipher(byte[] privateKey, byte[] publicKey, String algorithm, int opmode) {
      // 生成本地密钥
      SecretKey secretKey = getSecretKey(privateKey, publicKey, algorithm);

      try {
         // 数据加密
         Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
         cipher.init(opmode, secretKey);
         return cipher;
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }

   /**
    * 获得密钥
    * 
    * @param privateKey
    *           己方私钥
    * @param publicKey
    *           对方公钥
    * @param algorithm
    *           对称算法
    * @return
    */
   private static SecretKey getSecretKey(byte[] privateKey, byte[] publicKey, String algorithm) {
      try {
         KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
         PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
         Key priKey = keyFactory.generatePrivate(pkcs8KeySpec);

         KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
         keyAgree.init(priKey);
         keyAgree.doPhase(pubKey, true);

         // 生成本地密钥
         return keyAgree.generateSecret(algorithm);
      } catch (Exception e) {
         throw new JCodecException(e);
      }
   }
}

测试代码:

package com.jianggujin.codec.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyPair;

import org.junit.Test;

import com.jianggujin.codec.JBase64;
import com.jianggujin.codec.JBase64.JEncoder;
import com.jianggujin.codec.JDH;
import com.jianggujin.codec.JDH.JDHSymmetricalAlgorithm;

public class DHTest {
   String str = "jianggujin";
   File file = new File(getClass().getSimpleName() + ".dat");

   @Test
   public void test() throws Exception {
      System.out.println("原串:" + str);
      JEncoder encoder = JBase64.getEncoder();
      KeyPair keyPairA = JDH.initPartyAKey();
      byte[] keyPairAPrivate = keyPairA.getPrivate().getEncoded();
      byte[] keyPairAPublic = keyPairA.getPublic().getEncoded();
      System.out.println("甲方私钥:" + encoder.encodeToString(keyPairAPrivate, "UTF-8"));
      System.out.println("甲方公钥:" + encoder.encodeToString(keyPairAPublic, "UTF-8"));
      KeyPair keyPairB = JDH.initPartyBKey(keyPairAPublic);
      byte[] keyPairBPrivate = keyPairB.getPrivate().getEncoded();
      byte[] keyPairBPublic = keyPairB.getPublic().getEncoded();
      System.out.println("乙方私钥:" + encoder.encodeToString(keyPairBPrivate, "UTF-8"));
      System.out.println("乙方公钥:" + encoder.encodeToString(keyPairBPublic, "UTF-8"));
      for (JDHSymmetricalAlgorithm algorithm : JDHSymmetricalAlgorithm.values()) {
         System.out.println("-----------------------------------------");
         System.out.println("对称算法:" + algorithm.getName());
         byte[] encrypt = JDH.encrypt(str.getBytes(), keyPairAPrivate, keyPairBPublic, algorithm.getName());
         System.out.println("加密:" + encoder.encodeToString(encrypt, "UTF-8"));
         System.out
               .println("解密:" + new String(JDH.decrypt(encrypt, keyPairBPrivate, keyPairAPublic, algorithm.getName())));

         System.out.print("输出流加密:" + file.getAbsolutePath());
         OutputStream out = JDH.wrap(new FileOutputStream(file), keyPairAPrivate, keyPairBPublic, algorithm.getName());
         out.write(str.getBytes());
         out.flush();
         out.close();
         System.out.println();
         System.out.print("输入流解密:");
         InputStream in = JDH.wrap(new FileInputStream(file), keyPairBPrivate, keyPairAPublic, algorithm.getName());
         byte[] buffer = new byte[1024];
         int len = in.read(buffer);
         System.out.println(new String(buffer, 0, len));
      }
   }
}

测试结果:
原串:jianggujin
甲方私钥:MIIBZwIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoCAgIABEMCQQCKZ/IM4bTS0YkWGsMGFY6NAAICuvHpvhSBaPZ3Le4PS/owyrEnsiS3AXig5OYYko/fVvIBz1kOaKTl/0tsQLtt
甲方公钥:MIIBpzCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoCAgIAA4GFAAKBgQClQTWNc/3DBQQvs/KHwJ6CC9lYT2Cr2NdSHBUFiCuAUhQ7vpEgzL14IrhqJqixtMuOKOAOUOFBipavJTwhXNnviRNHQ0TJ1l+2ZNQaXHLQdpkBSl5E0fR7DRigbHUeNso52ZrNkDpyR0d7a6XQQRw9Ffig1ZujtO2+D7Ka2F8EJg==
乙方私钥:MIIBZwIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoCAgIABEMCQQDfg2OOQ+Rz4eRaatC0AKhNtA5i7KIrss7uM7Vtv2ls7zRCKWwXP5nRdbZAlO96tS1vF9AIZsYI82e8fQSBVfbX
乙方公钥:MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoCAgIAA4GEAAKBgDtzbZB/0vIobewwv7mUGGS54TBuNGf6wl3lLsAfTKylvzD2//qPqTJVXBGy9ZInHMYOwLb5nn85l8oULoXsp0uwZe2cFpmgJfRFpRD2FH+ZahBbtb7zgdsB30t0y42Qed+bL/o8znzv5yE1E6/z2iQdKhCRc52254hWgUVDkrH5
—————————————–
对称算法:DES
加密:zBJhlhWDFme0qIlClaBUQw==
解密:jianggujin
输出流加密:F:\workspace\java\eclipse\JCodec\DHTest.dat
输入流解密:jianggujin
—————————————–
对称算法:DESede
加密:0TFsnTdcA3JuJH2ZYn1ZcQ==
解密:jianggujin
输出流加密:F:\workspace\java\eclipse\JCodec\DHTest.dat
输入流解密:jianggujin

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
### 回答1: Diffie-Hellman算法是一种用于在不安全的公共信道上安全地交换密钥的算法。在C语言中,可以使用OpenSSL库来实现Diffie-Hellman算法。例如,可以使用以下代码来生成公钥和私钥: ```c #include <openssl/dh.h> DH *dh = DH_new(); DH_generate_parameters_ex(dh, 128, DH_GENERATOR_2, NULL); DH_generate_key(dh); ``` 然后可以使用以下代码来使用这对密钥进行加密解密: ```c unsigned char *shared_secret; int secret_size; secret_size = DH_compute_key(shared_secret, peer_public_key, dh); ``` 记住要处理好内存的分配和释放。 ### 回答2: Diffie-Hellman算法是一种非对称加密算法,其基本思想是通过数学运算来生成加密密钥,使得发送方和接收方可以安全地进行信息交换,保证信息的机密性。 Diffie-Hellman算法的核心是求出一个大质数p和一个大小为g<p的随机整数g,公开p和g,发送方选择一个私有数a,然后计算g^a mod p得到A,并将A发送给接收方。接收方也选择一个私有数b,然后计算g^b mod p得到B,并将B发送给发送方。随后,发送方计算B^a mod p,接收方计算A^b mod p,最终两端得到的结果相同,这个结果就是共享的密钥K。 在C语言中实现Diffie-Hellman算法,首先需要实现大数的计算。这可以通过自定义结构体来实现,结构体中包含一个数组,数组中存储每一位的值。然后可以使用库函数来实现大数的加减乘除等运算。 接下来,按照上述步骤实现Diffie-Hellman算法。需要生成一个大质数和一个随机数,可以使用rand()函数来生成随机数。然后,按照上述步骤计算出A和B,最后计算出共享密钥K。 实现时需要注意一些细节,比如计算A和B时需要进行模运算,这可以使用库函数来实现。还需要保证生成的质数p和随机数g的足够大,以保证安全性。 总之,Diffie-Hellman算法在网络传输中发挥了很大的作用,是一种非常重要的加密算法。在C语言中实现也是可行的,需要掌握大数计算和模运算等知识。 ### 回答3: Diffie-Hellman算法是一种密钥交换算法,用于在双方不存在密钥的情况下,通过公开通道建立共享秘密。Diffie-Hellman算法可以分为两个部分:密钥交换部分和密钥推导部分。密钥交换部分的流程如下: 1. 首先,双方协议选择一个大素数p和一个小于p的整数g作为公共参数,并将它们公开。 2. 每个参与者选定一个私密的随机数a(Alice)和b(Bob)。 3. Alice计算g^a%p,将计算结果发送给Bob,并保持a秘密。 4. Bob计算g^b%p,将计算结果发送给Alice,并保持b秘密。 5. 双方利用公式计算共享秘密s,s=g^(ab)%p。 密钥推导部分的流程如下: 1. 将收到的公开参数p、g和双方选定的私密值a、b代入公式计算共享秘密s。 2. 利用共享秘密s作为对称密钥。 3. 利用对称密钥加密通信内容。 Diffie-Hellman算法的安全性基于数学上的离散对数难题,即在p和g已知的情况下,计算g^(ab)模p的结果非常容易,但要从g和g^a%p、g^b%p中推导出共享秘密s则非常困难。因此,只有Alice和Bob知道私密值a和b才能推导出共享秘密s,保证了密钥安全性。 在C语言中,Diffie-Hellman算法可以通过调用openssl库来实现。具体的实现过程需要使用DH结构体来包含Diffie-Hellman算法相关的参数以及密钥交换和密钥推导的函数。代码示例如下: DH *dh = DH_new(); DH_generate_parameters_ex(dh,LEN,DH_GENERATOR_2,NULL); DH_generate_key(dh); 其中LEN是指DH算法中素数p的长度,可以根据需要修改。DH_generate_parameters_ex函数根据给定的参数生成DH结构体实例,并计算出公共参数p和g;DH_generate_key函数根据计算出的p和g以及自己选定的私密值a,计算出共享秘密s,并将s存储在DH结构体的公共参数中,以供对方获取。在实际应用中,需要将DH结构体、p、g、a等信息发送给对方,接收对方的信息并计算出共享秘密s,并用s作为对称密钥加密通信内容。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值