[JAVA加解密]RSA算法、ElGamal算法

一、RSA算法:

1、简介:RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。但在分布式计算和量子计算机理论日趋成熟的今天,RSA加密安全性受到了挑战。
RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥

RSA也是目前唯一一个基于因式分解难题的算法。


2、算法描述:RSA的算法涉及三个参数,n、e1、e2。
其中,n是两个大质数p、q的积,n的二进制表示时所占用的位数,就是所谓的密钥长度。
e1和e2是一对相关的值,e1可以任意取,但要求e1与(p-1)*(q-1)互质;再选择e2,要求(e2*e1)mod((p-1)*(q-1))=1。
(n,e1),(n,e2)就是密钥对。其中(n,e1)为公钥,(n,e2)为私钥。[1] 
RSA加解密的算法完全相同,设A为明文,B为密文,则:A=B^e2 mod n;B=A^e1 mod n;(公钥加密体制中,一般用公钥加密,私钥解密)
e1和e2可以互换使用,即:
A=B^e1 mod n;B=A^e2 mod n;


3、算法实现:

RSA算法实现较简单,没有什么需要特别注意的地方,以下代码仅进行了私钥加密,公钥解密,可用作数字签名使用;

public abstract class RSACoder {
	private static final String KEY_ALGORITHM= "RSA";
	private static final int KEY_SIZE=512;
	private static final String PUBLIC_KEY = "RSAPublicKey";
	private static final String PRIVATE_KEY = "RSAPrivateKey";
	
	public static Map<String,Object> initKey() throws NoSuchAlgorithmException{
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		keyPairGen.initialize(KEY_SIZE);
		KeyPair keyPair = keyPairGen.generateKeyPair();
		//生成密钥当然要生成最丰富的啦
		RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
		RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
		
		Map<String,Object> keyMap = new HashMap<String,Object>(2);
		keyMap.put(PUBLIC_KEY, publicKey);
		keyMap.put(PRIVATE_KEY, privateKey);
		return keyMap;
		
	}
	
	public static byte[] encryptByPrivateKey(byte[] data,byte[] priKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
		PKCS8EncodedKeySpec x509EncodedKeySpec = new PKCS8EncodedKeySpec(priKey);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PrivateKey privateKey = keyFactory.generatePrivate(x509EncodedKeySpec);
		
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);
		return cipher.doFinal(data);
		
	}
	
	public static byte[] decryptByPublicKey(byte[] data,byte[] pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
		X509EncodedKeySpec pkcs8EncodedKeySpec = new X509EncodedKeySpec(pubKey);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PublicKey publicKey = keyFactory.generatePublic(pkcs8EncodedKeySpec);
		
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, publicKey);
		return cipher.doFinal(data);
	}
	
	public static byte[] getPrivateKey(Map<String,Object> keyMap){
		RSAPrivateKey privateKey = (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
		return privateKey.getEncoded();
	}
	
	public static byte[] getPublicKey(Map<String,Object> keyMap){
		RSAPublicKey publicKey = (RSAPublicKey)keyMap.get(PUBLIC_KEY);
		return publicKey.getEncoded();
	}
}
测试用例:

public class RSACoderTest {
	private byte[] privateKey;
	private byte[] publicKey;
	
	@Before
	public void initKey() throws NoSuchAlgorithmException{
		Map<String,Object> keyMap = RSACoder.initKey();
		publicKey = RSACoder.getPublicKey(keyMap);
		privateKey = RSACoder.getPrivateKey(keyMap);
		System.err.println("公钥:\n"+Base64.encodeBase64String(publicKey));
		System.err.println("私钥:\n"+Base64.encodeBase64String(privateKey));
		
	}
	
	@Test
	public void test() throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
		System.err.println("\n--私钥加密,公钥解密--");
		String input1 = "RSA加密算法";
		System.err.println("原文:\n"+input1);
		byte[] data1 = input1.getBytes();
		byte[] encodedata1 = RSACoder.encryptByPrivateKey(data1, privateKey);
		System.err.println("加密后:\n"+Base64.encodeBase64String(encodedata1));
		byte[] decodedata1 = RSACoder.decryptByPublicKey(encodedata1, publicKey);
		System.err.println("解密后:\n"+Base64.encodeBase64String(decodedata1));
		String output1 = new String(decodedata1);
		System.out.println("结果:\n"+output1);
		assertEquals(input1,output1);
	}

}
输出:

公钥:
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIVn3mmbLJ35bRW51IM6voFzBcpIhhts85OlQJDTSdisfaEt9BRHOoTy2ND31oirr2gA/fGEEVWZvFgVyoz/8Y8CAwEAAQ==
私钥:
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAhWfeaZssnfltFbnUgzq+gXMFykiGG2zzk6VAkNNJ2Kx9oS30FEc6hPLY0PfWiKuvaAD98YQRVZm8WBXKjP/xjwIDAQABAkARdQYly6iLA5jCvw6QHZ/QULzxO4xRCnDVYUqRqRSAxeEtUGv7rTdzvmD4e7sNnnmgdzJA4Tw6WFqI32e1UtgBAiEAxn8AWQuJ1LjC/Uvk90bh1J9rvLZAn22SV9z0TS3I45kCIQCsDZfV5Zl7vTT4cwXe+lcC7z6504R8i7aHyaPcRoq3ZwIgCYQxOhOpif9JqecnlQta7FywR53dP0d7iqbXN5QIW5ECIQCmWdo1aHH2ruC5W1UQ21EnuDQYrYcKeHc6YN56ywWx/wIgRzHu0AmIjaG94ihMBWvAywO/xetdY9tSQZpSHFSKLnU=


--私钥加密,公钥解密--
原文:
RSA加密算法
加密后:
BltYXEfVGzfd78ejw70kIQ3eapFzZmb69i4LYdU5gopS4FtDNnshhkMiNTkzO8MVLKyHtsp6XCg+8fZ0GHcSUw==
解密后:
UlNBvNPD3Mvjt6g=
结果:
RSA加密算法



小结:

1、RSA算法公钥远远小于私钥;

2、Cipher.init()中参数第二为Key类型即可,还原Key类型即可;

3、getPrivateKey及getPublicKey都是通过传入Map参数取得结果的;

4、PKCS8EncodedKeySpec是还原私钥的,尽管PKCS是这个The Public-Key Cryptography Standards



二、ElGamal密码体系:

本部分注重一个问题:ElGamal密钥的生成

JAVA7不支持。引入BouncyCastle

 下面是教程提供的基于DHParameterSpec算法参数材料创建密钥

public static Map<String,Object> initKey() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException{
		Security.addProvider(new BouncyCastleProvider());
		AlgorithmParameterGenerator apg =AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
		apg.init(KEY_SIZE);
		AlgorithmParameters params = apg.generateParameters();
		DHParameterSpec dhParams = params.getParameterSpec(DHParameterSpec.class);
		
		KeyPairGenerator keyPairGene = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		keyPairGene.initialize(dhParams, new SecureRandom());
		
		KeyPair keyPair = keyPairGene.generateKeyPair();
		PublicKey publicKey = keyPair.getPublic();
		PrivateKey privateKey = keyPair.getPrivate();
		
		Map<String,Object> keyMap = new HashMap<String,Object>(2);
		keyMap.put(PUBLIC_KEY, publicKey);
		keyMap.put(PRIVATE_KEY, privateKey);
		return keyMap;
	}

经过试验,按照往常的套路,这样的代码也是可行的:

	public static Map<String,Object> initKey() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException{
		Security.addProvider(new BouncyCastleProvider());
		KeyPairGenerator keyPairGene = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		keyPairGene.initialize(KEY_SIZE, new SecureRandom());
		KeyPair keyPair = keyPairGene.generateKeyPair();
		PublicKey publicKey = keyPair.getPublic();
		PrivateKey privateKey = keyPair.getPrivate();
		
		Map<String,Object> keyMap = new HashMap<String,Object>(2);
		keyMap.put(PUBLIC_KEY, publicKey);
		keyMap.put(PRIVATE_KEY, privateKey);
		return keyMap;
	}

而两种方法的关键都在于KeyPairGenerator类的init()函数:

Class KeyPairGenerator

void initialize(AlgorithmParameterSpec params)
Initializes the key pair generator using the specified parameter set and the  SecureRandomimplementation of the highest-priority installed provider as the source of randomness.
void initialize(AlgorithmParameterSpec params, SecureRandom random)
Initializes the key pair generator with the given parameter set and source of randomness.
void initialize(int keysize)
Initializes the key pair generator for a certain keysize using a default parameter set and the SecureRandom implementation of the highest-priority installed provider as the source of randomness.
void initialize(int keysize, SecureRandom random)
Initializes the key pair generator for a certain keysize with the given source of randomness (and a default parameter set).

Interface AlgorithmParameterSpec

public class AlgorithmParameters
extends Object

两者没有半毛钱关系


再需要注意的是ElGamal需要随机数的,详细可参照加密原理,传输密钥对有乙方选择的随机数k


最后,实现代码如下:

public abstract class ElGamalCoder {
	public static final String KEY_ALGORITHM="ElGamal";
	private static final int KEY_SIZE=256;
	private static final String PUBLIC_KEY="ElGamalPublicKey";
	private static final String PRIVATE_KEY = "ElGamalPrivateKey";
	
	public static byte[] decryptByPrivateKey(byte[] data,byte[]key) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
		Security.addProvider(new BouncyCastleProvider());
		PKCS8EncodedKeySpec pkc = new PKCS8EncodedKeySpec(key);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key privateKey = keyFactory.generatePrivate(pkc);
		
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		return cipher.doFinal(data);
		
	}
	
	public static byte[] encryptByPublicKey(byte[] data,byte[]key) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
		Security.addProvider(new BouncyCastleProvider());
		X509EncodedKeySpec x509 = new X509EncodedKeySpec(key);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key publicKey = keyFactory.generatePublic(x509);
		
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		return cipher.doFinal(data);
		
	}
	
	public static Map<String,Object> initKey() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException{
		Security.addProvider(new BouncyCastleProvider());
		AlgorithmParameterGenerator apg =AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
		apg.init(KEY_SIZE);
		AlgorithmParameters params = apg.generateParameters();
		DHParameterSpec dhParams = params.getParameterSpec(DHParameterSpec.class);
		
		KeyPairGenerator keyPairGene = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		keyPairGene.initialize(dhParams, new SecureRandom());
	
//		keyPairGene.initialize(KEY_SIZE, new SecureRandom());
		KeyPair keyPair = keyPairGene.generateKeyPair();
		PublicKey publicKey = keyPair.getPublic();
		PrivateKey privateKey = keyPair.getPrivate();
		
		Map<String,Object> keyMap = new HashMap<String,Object>(2);
		keyMap.put(PUBLIC_KEY, publicKey);
		keyMap.put(PRIVATE_KEY, privateKey);
		return keyMap;
	}
	
	public static byte[] getPrivateKey(Map<String,Object> keyMap){
		Key key = (Key) keyMap.get(PRIVATE_KEY);
		return key.getEncoded();
	}
	
	public static byte[] getPublicKey(Map<String,Object> keyMap){
		Key key = (Key) keyMap.get(PUBLIC_KEY);
		return key.getEncoded();
	}
}

public class ElGamalCoderTest {
	private byte[] privateKey;
	private byte[] publicKey;
	
	@Before
	public void initKey() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException{
		Map<String,Object> keyMap = ElGamalCoder.initKey();
		publicKey = ElGamalCoder.getPublicKey(keyMap);
		privateKey = ElGamalCoder.getPrivateKey(keyMap);
		System.err.println("公钥:\n"+Base64.encodeBase64String(publicKey));
		System.err.println("私钥:\n"+Base64.encodeBase64String(privateKey));
		
	}
	
	@Test
	public void test() throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
		System.err.println("\n--公钥加密,私钥解密--");
		String input1 = "ElGamal加密算法";
		System.err.println("原文:\n"+input1);
		byte[] data1 = input1.getBytes();
		byte[] encodedata1 = ElGamalCoder.encryptByPublicKey(data1, publicKey);
		System.err.println("加密后:\n"+Base64.encodeBase64String(encodedata1));
		byte[] decodedata1 = ElGamalCoder.decryptByPrivateKey(encodedata1, privateKey);
		System.err.println("解密后:\n"+Base64.encodeBase64String(decodedata1));
		String output1 = new String(decodedata1);
		System.err.println("结果:\n"+output1);
		assertEquals(input1,output1);
	}

}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ElGamal算法是一种非对称加密算法,与RSA算法类似,它也是基于数论的,但是与RSA算法不同的是它的加密和解密使用的是同一个密钥对,而且加密和解密过程都需要进行一些随机化处理。 下面是ElGamal算法加解密C语言实现: 加密过程: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> // 求模幂运算 a^b mod m long long mod_pow(long long a, long long b, long long m) { long long ans = 1; while (b > 0) { if (b & 1) { ans = (ans * a) % m; } a = (a * a) % m; b >>= 1; } return ans; } // 生成一个大素数 long long get_prime(long long min, long long max) { long long i, j; for (i = min; i <= max; i++) { for (j = 2; j <= sqrt(i); j++) { if (i % j == 0) { break; } } if (j > sqrt(i)) { return i; } } return -1; } // 生成一个随机数 long long get_random(long long min, long long max) { return rand() % (max - min + 1) + min; } int main() { long long p, g, x, y, k, m, c1, c2; srand(time(0)); // 生成大素数 p p = get_prime(10000, 20000); // 选择一个原根 g for (g = 2; g < p; g++) { int flag = 1; for (int i = 1; i < p - 1; i++) { if (mod_pow(g, i, p) == 1) { flag = 0; break; } } if (flag) { break; } } // 生成私钥 x x = get_random(2, p - 2); // 计算公钥 y y = mod_pow(g, x, p); // 加密 printf("请输入要加密的明文:"); scanf("%lld", &m); k = get_random(2, p - 2); c1 = mod_pow(g, k, p); c2 = m * mod_pow(y, k, p) % p; printf("密文为:(%lld, %lld)\n", c1, c2); return 0; } ``` 解密过程: ```c #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> // 求模幂运算 a^b mod m long long mod_pow(long long a, long long b, long long m) { long long ans = 1; while (b > 0) { if (b & 1) { ans = (ans * a) % m; } a = (a * a) % m; b >>= 1; } return ans; } int main() { long long p, x, c1, c2, m; scanf("%lld%lld%lld%lld", &p, &x, &c1, &c2); // 解密 m = c2 * mod_pow(c1, p - 1 - x, p) % p; printf("明文为:%lld\n", m); return 0; } ``` 其中,加密过程中,首先生成一个大素数p,然后选择一个原根g,然后生成私钥x和公钥y。加密时,选择一个随机数k,计算密文c1和c2。解密时,根据公式,将密文c1、c2、私钥x和大素数p带入即可计算出明文m。 需要注意的是,由于ElGamal算法加密过程中需要进行随机化处理,因此同样的明文在不同的加密过程中得到的密文是不同的,这也是ElGamal算法的特点之一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值