Merge pull request #3131 from 0x00stone/v5-dev

添加 同态加密算法 Paillierr
This commit is contained in:
Golden Looly 2023-06-09 17:35:19 +08:00 committed by GitHub
commit 84621a71e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 345 additions and 0 deletions

View File

@ -0,0 +1,195 @@
package cn.hutool.crypto.asymmetric;
import cn.hutool.core.util.HexUtil;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;
/**
* 同态加密算法Paillier
*
* 加法同态存在有效算法+E(x+y)=E(x)+E(y)或者 x+y=D(E(x)+E(y))成立并且不泄漏 x y
* 乘法同态存在有效算法*E(x×y)=E(x)*E(y)或者 xy=D(E(x)*E(y))成立并且不泄漏 x y
*
* 方案安全性可以归约到判定性合数剩余假设Decisional Composite Residuosity Assumption, DCRA即给定一个合数n和整数z判定z是否在n^2下是否是n次剩余是困难的
* 这个假设经过了几十年的充分研究到目前为止还没有多项式时间的算法可以攻破所以Paillier加密方案的安全性被认为相当可靠
*
* 字符串文本加解密相互配对,此时无法使用同态加法和同态乘法
* 数值类型不可使用字符串加解密
*
* 公钥加密和同态加法/同态乘法运算
* 私钥解密
*
* @author Revers.
**/
public class Paillier {
//公钥 n g
//私钥 n lambda u
private static int bitLength = 2048;
private static int certainty = 256;
/**
* 生成密钥算法默认
* @return PaillierKeyPair 公钥私钥对
*/
public static final PaillierKeyPair generateKey() {
return generateKey(bitLength,certainty);
}
/**
* 生成密钥算法
*
* @param bitLength 密钥位数
* @param certainty 此构造函数的执行时间与此参数的值成比例
* @return PaillierKeyPair 公钥私钥对
*/
public static final PaillierKeyPair generateKey(int bitLength,int certainty) {
BigInteger p =new BigInteger(bitLength / 2, certainty, new SecureRandom());
BigInteger q =new BigInteger(bitLength / 2, certainty, new SecureRandom());
BigInteger n = p.multiply(q);
BigInteger nSquare = n.multiply(n);
BigInteger lambda = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE))
.divide(p.subtract(BigInteger.ONE).gcd(q.subtract(BigInteger.ONE)));
BigInteger g = n.add(BigInteger.ONE);
BigInteger u = g.modPow(lambda, nSquare).subtract(BigInteger.ONE).divide(n).modInverse(n);
PaillierpublicKey publicKey = new PaillierpublicKey(n,g);
PaillierPrivateKey privateKey = new PaillierPrivateKey(n, lambda,u);
PaillierKeyPair keyPair = new PaillierKeyPair(publicKey,privateKey);
return keyPair;
}
/**
* 字符串加密算法输入一个明文和一个公钥
* 只能使用字符串解密算法 decryptString 不可使用同态加法和同态乘法
*
* @param text 明文字符串形式
* @param publicKey 公钥
*
* @return byte[]密文
*/
public static final byte[] encryptString(String text, PaillierpublicKey publicKey) {
BigInteger r = new BigInteger(bitLength, new Random());
BigInteger n = publicKey.getN();
BigInteger nsquare = n.multiply(n);
return publicKey.getG().modPow( new BigInteger(HexUtil.encodeHexStr(text),16), nsquare).multiply(r.modPow(n, nsquare)).mod(nsquare).toByteArray();
}
/**
* 字符串解密算法输入一个密文和一个私钥
*
* @param ciphertext byte[]密文
* @param privateKey 私钥
* @return 解密的明文
*/
public static final String decryptString(byte[] ciphertext, PaillierPrivateKey privateKey) {
BigInteger n = privateKey.getN();
BigInteger lambda = privateKey.getLambda();
BigInteger u = privateKey.getu();
BigInteger nsquare = n.multiply(n);
String s = new BigInteger(ciphertext).modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).multiply(u).mod(n).toString();
return HexUtil.decodeHexStr(new BigInteger(s).toString(16));
}
/**
* 加密算法输入一个明文和一个公钥
*
* @param text 明文为防止字符串数据只能使用 BigInteger类型
* @param publicKey 公钥
* @return byte[]密文
*/
public static final byte[] encrypt(BigInteger text, PaillierpublicKey publicKey) {
BigInteger r = new BigInteger(bitLength, new Random());
BigInteger n = publicKey.getN();
BigInteger nsquare = n.multiply(n);
return publicKey.getG().modPow(text, nsquare).multiply(r.modPow(n, nsquare)).mod(nsquare).toByteArray();
}
/**
* 解密算法输入一个密文和一个私钥
*
* @param ciphertext byte[]密文
* @param privateKey 私钥
* @return 解密的明文
*/
public static final String decrypt(byte[] ciphertext, PaillierPrivateKey privateKey) {
BigInteger n = privateKey.getN();
BigInteger lambda = privateKey.getLambda();
BigInteger u = privateKey.getu();
BigInteger nsquare = n.multiply(n);
return new BigInteger(ciphertext).modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).multiply(u).mod(n).toString();
}
/**
* 同态标量加算法输入两个密文和一个公钥
*
* @param ciphertext 密文1BigInteger
* @param ciphertext2 密文2BigInteger
* @param publicKey 公钥
* @return byte[]密文
*/
public static final byte[] add(BigInteger ciphertext,BigInteger ciphertext2,PaillierpublicKey publicKey){
return ciphertext.add(ciphertext2).multiply(publicKey.getN()).toByteArray();
}
/**
* 同态标量加算法输入两个密文和一个公钥
*
* @param ciphertext 密文110进制字符串
* @param ciphertext2 密文210进制字符串
* @param publicKey 公钥
* @return byte[]密文
*/
public static final byte[] add(String ciphertext,String ciphertext2,PaillierpublicKey publicKey){
return new BigInteger(ciphertext).multiply(new BigInteger(ciphertext2)).mod(publicKey.getN().multiply(publicKey.getN())).toByteArray();
}
/**
* 同态标量加算法输入两个密文和一个公钥
*
* @param ciphertext byte[] 10进制字符串
* @param ciphertext2 byte[] 10进制字符串
* @param publicKey 公钥
* @return byte[]密文
*/
public static final byte[] add(byte[] ciphertext,byte[] ciphertext2,PaillierpublicKey publicKey){
return new BigInteger(ciphertext).multiply(new BigInteger(ciphertext2)).mod(publicKey.getN().multiply(publicKey.getN())).toByteArray();
}
/**
* 同态标量乘算法输入一个密文和一个标量明文和一个公钥
*
* @param ciphertext 密文BigInteger
* @param number 明文10进制字符串
* @param publicKey 公钥
* @return byte[]密文
*/
public static final byte[] multiply(BigInteger ciphertext,BigInteger number,PaillierpublicKey publicKey){
return ciphertext.modPow(number,publicKey.getN().multiply(publicKey.getN())).toByteArray();
}
/**
* 同态标量乘算法输入一个密文和一个标量明文和一个公钥
*
* @param ciphertext 密文byte[]
* @param number 明文10进制字符串
* @param publicKey 公钥
* @return byte[]密文
*/
public static final byte[] multiply(String ciphertext,BigInteger number,PaillierpublicKey publicKey){
return new BigInteger(ciphertext).modPow(number,publicKey.getN().multiply(publicKey.getN())).toByteArray();
}
/**
* 同态标量乘算法输入一个密文和一个标量明文和一个公钥
*
* @param ciphertext 密文byte[]
* @param number 明文10进制字符串
* @param publicKey 公钥
* @return byte[]密文
*/
public static final byte[] multiply(byte[] ciphertext,BigInteger number,PaillierpublicKey publicKey){
return new BigInteger(ciphertext).modPow(number,publicKey.getN().multiply(publicKey.getN())).toByteArray();
}
}

View File

@ -0,0 +1,32 @@
package cn.hutool.crypto.asymmetric;
/**
* 存放Paillier 公钥私钥对
*
* @author Revers.
**/
public class PaillierKeyPair {
private PaillierPrivateKey privateKey;
private PaillierpublicKey publicKey;
public PaillierKeyPair(PaillierpublicKey PaillierpublicKey,PaillierPrivateKey PaillierPrivateKey) {
this.privateKey = PaillierPrivateKey;
this.publicKey = PaillierpublicKey;
}
public PaillierPrivateKey getPrivateKey() {
return privateKey;
}
public void setPrivateKey(PaillierPrivateKey privateKey) {
this.privateKey = privateKey;
}
public PaillierpublicKey getPublicKey() {
return publicKey;
}
public void setPublicKey(PaillierpublicKey publicKey) {
this.publicKey = publicKey;
}
}

View File

@ -0,0 +1,39 @@
package cn.hutool.crypto.asymmetric;
import java.math.BigInteger;
/** 存放Paillier 私钥
*
* @author Revers.
**/
public class PaillierPrivateKey{
private final BigInteger n;
private final BigInteger lambda;
private final BigInteger u;
public PaillierPrivateKey(BigInteger n, BigInteger lambda, BigInteger u) {
if (n == null) {
throw new NullPointerException("n is null");
}
if (lambda == null) {
throw new NullPointerException("lambda is null");
}
if (u == null) {
throw new NullPointerException("u is null");
}
this.n = n;
this.lambda = lambda;
this.u = u;
}
public BigInteger getN() {
return n;
}
public BigInteger getLambda() {
return lambda;
}
public BigInteger getu() {
return u;
}
}

View File

@ -0,0 +1,30 @@
package cn.hutool.crypto.asymmetric;
import java.math.BigInteger;
/** 存放Paillier 公钥
*
* @author Revers.
**/
public class PaillierpublicKey{
private BigInteger n;
private BigInteger g;
public PaillierpublicKey(BigInteger n, BigInteger g) {
if (n == null) {
throw new NullPointerException("n is null");
}
if (g == null) {
throw new NullPointerException("g is null");
}
this.n = n;
this.g = g;
}
public BigInteger getN() {
return n;
}
public BigInteger getG() {
return g;
}
}

View File

@ -0,0 +1,49 @@
package cn.hutool.crypto.asymmetric;
import org.junit.Test;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
/**
* @author Revers.
**/
public class PaillierTest {
@Test
public void test() throws NoSuchAlgorithmException {
//生成 公钥和私钥
PaillierKeyPair paillierKeyPair = Paillier.generateKey();
PaillierpublicKey publicKey = paillierKeyPair.getPublicKey();
PaillierPrivateKey privateKey = paillierKeyPair.getPrivateKey();
//创建两个大整数m1,m2:
BigInteger m1 = new BigInteger("10");
BigInteger m2 = new BigInteger("40");
//公钥加密私钥解
byte[] em1 = Paillier.encrypt(m1, publicKey);
System.out.println("m1解密结果" + Paillier.decrypt(em1, privateKey));
//同态特性
byte[] em2 = Paillier.encrypt(m2, publicKey);
System.out.println("m1加密em1 :"+ new BigInteger(em1).toString(16));
System.out.println("m2加密em2 :"+ new BigInteger(em2).toString(16));
byte[] add = Paillier.add(em1, em2, publicKey);
System.out.println("m1+m2 密文的和:" + new BigInteger(add).toString(16));
System.out.println("m1+m2 密文的和的解:" + Paillier.decrypt(add,privateKey));
byte[] mul = Paillier.multiply(em1, m2, publicKey);
System.out.println("m1*m2 密文的积:" + new BigInteger(mul).toString(16));
System.out.println("m1*m2 密文的积的解:" + Paillier.decrypt(mul,privateKey));
//加解密字符串
String s = "123456dfsgsdg!@#%!@@#$!#%是豆腐干山豆根v啊微软";
System.out.println("字符串明文: "+s);
byte[] encrypt = Paillier.encryptString(s, publicKey);
System.out.println("字符串密文: "+ new BigInteger(encrypt).toString(16) );
String decrypt = Paillier.decryptString(encrypt, privateKey);
System.out.println("字符串密文解密: "+ decrypt);
}
}