加密之非对称RSA,DH,DSA,ECC
- 1 RSA算法
- 1.1 定义
- 1.2 原理
- 1.2.1 互质关系
- 1.2.2 欧拉函数
- 1.2.3 欧拉定理
- 1.2.4 模反元素
- 1.3 实际操作
- 1.3.1 生成公私钥并获取
- 1.3.2 公私钥加签验签
- 1.3.3 公私钥加密解密
- 1.3.4 结果验证
- 2 DH算法
- 2.1 定义
- 2.2 实际操作
- 2.2.1 生成甲乙公私钥
- 2.2.1.1 生成甲公私钥
- 2.2.1.2 根据甲公钥生成乙公私钥
- 2.2.1.3 获取公私钥
- 2.2.2 根据公私钥生成本地密钥
- 2.2.3 加密解密
- 2.2.4 结果验证
- 2.2.1 生成甲乙公私钥
- 3 DSA算法
- 3.1 定义
- 3.2 实际操作
- 3.2.1 生成公私钥并获取
- 3.2.2 加签验签
- 3.2.2.1 私钥加签
- 3.2.2.1 公钥验签
- 3.2.3 结果验证
- 4 ECC
- 4.1 定义
- 4.2 实际操作
- 4.2.1 生成公私钥并获取
- 4.2.2 加密解密
- 4.2.3 结果验证
1 RSA算法
1.1 定义
RSA
,这种算法1978年就出现了,它是第一个既能用于数据加密
也能用于数字签名
的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。
这种加密算法的特点主要是密钥的变化,DES只有一个密钥。相当于只有一把钥匙,如果这把钥匙丢了,数据也就不安全了。但是RSA
同时有两把钥匙,公钥
与私钥
。同时支持数字签名。数字签名的意义在于,对传输过来的数据进行校验。确保数据在传输工程中不被修改。
RSA
算法一直是最广为使用的非对称加密算法
。毫不夸张地说,只要有计算机网络的地方,就有RSA
算法。
这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA
密钥是768
个二进制位。也就是说,长度超过768
位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024
位的RSA
密钥基本安全,2048
位的密钥极其安全。
1.2 原理
流程分析:
甲方构建密钥对儿
,将公钥公布给乙方,将私钥保留。
甲方使用私钥加密数据,然后用私钥对加密后的数据签名,发送给乙方签名以及加密后的数据;乙方使用公钥、签名来验证待解密数据是否有效,如果有效使用公钥对数据解密。
乙方使用公钥加密数据,向甲方发送经过加密后的数据;甲方获得加密数据,通过私钥解密
1.2.1 互质关系
如果两个正整数,除了1
以外,没有其他公因子
,我们就称这两个数是互质关系
(coprime)。比如,15和32没有公因子,所以它们是互质关系。这说明,不是质数也可以构成互质关系。
关于互质关系,不难得到以下结论:
- 任意两个质数构成互质关系,比如13和61。
- 一个数是质数,另一个数只要不是前者的倍数,两者就构成互质关系,比如3和10。
- 如果两个数之中,较大的那个数是质数,则两者构成互质关系,比如97和57。
- 1和任意一个自然数是都是互质关系,比如1和99。
- p是大于1的整数,则p和p-1构成互质关系,比如57和56。
- p是大于1的奇数,则p和p-2构成互质关系,比如17和15
1.2.2 欧拉函数
请思考以下问题:
任意给定正整数n
,请问在小于等于n
的正整数之中,有多少个与n
构成互质关系?(比如,在1到8之中,有多少个数与8
构成互质关系?)
计算这个值的方法就叫做欧拉函数
,以φ(n)
表示。在1
到8
之中,与8
形成互质关系的是1、3、5、7
,所以 φ(n) = 4
φ(n)
的计算方法并不复杂,但是为了得到最后那个公式,需要一步步讨论。
第一种情况
如果n=1
,则 φ(1) = 1
。因为1与任何数(包括自身)都构成互质关系。
第二种情况
如果n
是质数,则 φ(n)=n-1
。因为质数与小于它的每一个数,都构成互质关系。比如5与1、2、3、4都构成互质关系。
第三种情况
如果n
是质数的某一个次方,即 n = p^k
(p
为质数,k
为大于等于1
的整数),则
比如 φ(8) = φ(2^3) =2^3 - 2^2 = 8 -4 = 4
这是因为只有当一个数不包含质数p
,才可能与n
互质。而包含质数p
的数一共有p^(k-1)
个,即1×p、2×p、3×p、...、p^(k-1)×p
,把它们去除,剩下的就是与n
互质的数。
上面的式子还可以写成下面的形式:
可以看出,上面的第二种情况是 k=1
时的特例。
第四种情况
如果n
可以分解成两个互质的整数之积,n = p1 × p2
则 φ(n) = φ(p1p2) = φ(p1)φ(p2)
即积的欧拉函
数等于各个因子的欧拉函数之积。比如,φ(56)=φ(8×7)=φ(8)×φ(7)=4×6=24
这一条的证明要用到"中国剩余定理",这里就不展开了,只简单说一下思路:如果a
与p1
互质(a
因为任意一个大于1的正整数,都可以写成一系列质数的积。
根据第4条的结论,得到
再根据第3条的结论,得到
也就等于
这就是欧拉函数的通用计算公式。比如,1323的欧拉函数,计算过程如下:
1.2.3 欧拉定理
欧拉函数的用处,在于欧拉定理。欧拉定理
指的是:
如果两个正整数a
和n
互质,则n
的欧拉函数 φ(n)
可以让下面的等式成立:
也就是说,a
的φ(n)
次方被n
除的余数为1
。或者说,a
的φ(n)
次方减去1
,可以被n整除。比如,3和7互质,而7的欧拉函数φ(7)
等于6,所以3的6次方(729)减去1,可以被7整除(728/7=104)。
欧拉定理的证明比较复杂,这里就省略了。我们只要记住它的结论就行了。
欧拉定理可以大大简化某些运算。比如,7和10互质,根据欧拉定理,
已知 φ(10)
等于4
,所以马上得到7
的4
倍数次方的个位数肯定是1。
因此,7的任意次方的个位数(例如7的222次方),心算就可以算出来。
欧拉定理有一个特殊情况。
假设正整数a
与质数p
互质,因为质数p
的φ(p)
等于p-1
,则欧拉定理可以写成
这就是著名的费马小定理。它是欧拉定理的特例。
欧拉定理是RSA算法的核心。理解了这个定理,就可以理解RSA。
1.2.4 模反元素
还剩下最后一个概念:
如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。
这时,b就叫做a的模反元素
比如,3和11互质,那么3的模反元素就是4
,因为 (3 × 4)-1 可以被11整除。显然,模反元素不止一个, 4加减11的整数倍都是3的模反元素 {...,-18,-7,4,15,26,...},即如果b是a的模反元素,则 b+kn 都是a的模反元素。
欧拉定理可以用来证明模反元素必然存在。
可以看到,a的 φ(n)-1 次方,就是a的模反元素。
1.3 实际操作
下面代码用到的常量:
static BASE64Decoder de = new BASE64Decoder();
static BASE64Encoder en = new BASE64Encoder();
public static final String KEY_ALGORITHM = "RSA";
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
private static final String PUBLIC_KEY = "RSAPublicKey";
private static final String PRIVATE_KEY = "RSAPrivateKey";
1.3.1 生成公私钥并获取
/**
* 初始化密钥
*/
public static Map initKey() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
// 公钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// 私钥
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map keyMap = new HashMap(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 取得私钥
* @throws Exception
*/
public static String getPrivateKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return en.encode(key.getEncoded());
}
/**
* 取得公钥
*/
public static String getPublicKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return en.encode(key.getEncoded());
}
1.3.2 公私钥加签验签
/**
* 用私钥对信息生成数字签名
* @param data 加密数据
* @param privateKey 私钥
*/
public static String sign(byte[] data, String privateKey) throws Exception {
// 解密由base64编码的私钥
byte[] keyBytes = de.decodeBuffer(privateKey);
// 构造PKCS8EncodedKeySpec对象
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 取私钥匙对象
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 用私钥对信息生成数字签名
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(priKey);
signature.update(data);
return en.encode(signature.sign());
}
/**
* 公钥校验数字签名
* @param data 加密数据
* @param publicKey 公钥
* @param sign 数字签名
* @return 校验成功返回true 失败返回false
*/
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
// 解密由base64编码的公钥
byte[] keyBytes = de.decodeBuffer(publicKey);
// 构造X509EncodedKeySpec对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 取公钥匙对象
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(data);
// 验证签名是否正常
return signature.verify(de.decodeBuffer(sign));
}
1.3.3 公私钥加密解密
/**
* 加密
* 用私钥加密
* @param data
* @param key
*/
public static String decryptByPrivateKey(byte[] data, String key) throws Exception {
// 对密钥解密
byte[] keyBytes = de.decodeBuffer(key);
// 取得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 对数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(data));
}
/**
* 加密
* 用公钥加密
* @param data
* @param key
*/
public static String decryptByPublicKey(byte[] data, String key) throws Exception {
// 对密钥解密
byte[] keyBytes = de.decodeBuffer(key);
// 取得公钥
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
// 对数据解密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return new String(cipher.doFinal(data));
}
/**
* 加密
* 用公钥加密
* @param data
* @param key
* @return
* @throws Exception
*/
public static String encryptByPublicKey(byte[] data, String key) throws Exception {
// 对公钥解密
byte[] keyBytes = de.decodeBuffer(key);
// 取得公钥
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return en.encode(cipher.doFinal(data));
}
/**
* 加密
* 用私钥加密
*
* @param data
* @param key
* @return
* @throws Exception
*/
public static String encryptByPrivateKey(byte[] data, String key) throws Exception {
// 对密钥解密
byte[] keyBytes = de.decodeBuffer(key);
// 取得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return en.encode(cipher.doFinal(data));
}
1.3.4 结果验证
public static void main(String[] args) throws Exception{
//生成 公钥私钥
Map keyMap = initKey();
String publicKey = getPublicKey(keyMap);
String privateKey = getPrivateKey(keyMap);
System.err.println("公钥: \n\r" + publicKey);
System.err.println("私钥: \n\r" + privateKey);
System.err.println("公钥加密——私钥解密");
String inputStr = "abc";
byte[] data = inputStr.getBytes();
String encodedData = encryptByPublicKey(data, publicKey);
String decodedData = decryptByPrivateKey(de.decodeBuffer(encodedData),privateKey);
System.err.println("加密前: " + inputStr +"\n\r" +"加密中: "+encodedData+"\n\r" + "解密后: " + decodedData);
System.err.println("公钥加密——私钥解密");
System.err.println("私钥加密——公钥解密");
String inputStr_new = "sign";
byte[] data_new = inputStr_new.getBytes();
String encodedData_new = encryptByPrivateKey(data_new, privateKey);
String decodedData_new =decryptByPublicKey(de.decodeBuffer(encodedData_new), publicKey);
System.err.println("加密前: " + inputStr_new + "\n\r" +"加密中: "+encodedData_new+"\n\r" + "解密后: " + decodedData_new);
System.err.println("私钥加密——公钥解密");
System.err.println("私钥签名——公钥验证签名");
// 产生签名
String sign = sign(encodedData_new.getBytes(), privateKey);
System.err.println("签名:\r\n" + sign);
// 验证签名
boolean status = verify(encodedData_new.getBytes(), publicKey, sign);
System.err.println("状态:\r\n" + status);
System.err.println("私钥签名——公钥验证签名");
}
2 DH算法
2.1 定义
接下来我们分析DH
加密算法,一种适基于密钥
一致协议的加密算法。
Diffie-Hellman
算法(D-H
算法),密钥一致协议
,非对称加密算法。
是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成一致的、可以共享的密钥
。换句话说,就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey
)对数据加密。这样,在互通了本地密钥(SecretKey
)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!该算法源于中国的同余定理——中国馀数定理
流程分析:
- 甲方构建密钥对儿,将公钥公布给乙方,将私钥保留;双方约定数据加密算法;乙方通过甲方公钥构建密钥对儿,将公钥公布给甲方,将私钥保留。
- 甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给乙方加密后的数据;乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。
- 乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给甲方加密后的数据;甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。
2.2 实际操作
下面代码用到的常量
/**
* 默认密钥字节数
* Default Keysize 1024
*/
private static final int KEY_SIZE = 1024;
public static final String ALGORITHM = "DH";
/**
* DH加密下需要一种对称加密算法对数据加密,这里我们使用DES,也可以使用其他对称加密算法。
*/
public static final String SECRET_ALGORITHM = "DES";
private static final String PUBLIC_KEY = "DHPublicKey";
private static final String PRIVATE_KEY = "DHPrivateKey";
static BASE64Decoder de = new BASE64Decoder();
static BASE64Encoder en = new BASE64Encoder();
2.2.1 生成甲乙公私钥
2.2.1.1 生成甲公私钥
/**
* 初始化甲方密钥
*/
public static Map initKey() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 甲方公钥
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
// 甲方私钥
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
Map keyMap = new HashMap(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
2.2.1.2 根据甲公钥生成乙公私钥
/**
* 使用甲方公钥====初始化乙方密钥
*/
public static Map initKey(String key) throws Exception {
// 解析甲方公钥
byte[] keyBytes = de.decodeBuffer(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
// 由甲方公钥====构建乙方密钥
DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
keyPairGenerator.initialize(dhParamSpec);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 乙方公钥
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
// 乙方私钥
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
Map keyMap = new HashMap(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
2.2.1.3 获取公私钥
/**
* 取得私钥
*/
public static String getPrivateKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return en.encode(key.getEncoded());
}
/**
* 取得公钥
*/
public static String getPublicKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return en.encode((key.getEncoded()));
}
2.2.2 根据公私钥生成本地密钥
/**
* 构建密钥
*
* @param publicKey 公钥
* @param privateKey 私钥
*/
private static SecretKey getSecretKey(String publicKey, String privateKey) throws Exception {
// 初始化公钥
byte[] pubKeyBytes = de.decodeBuffer(publicKey);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKeyBytes);
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
// 初始化私钥
byte[] priKeyBytes = de.decodeBuffer(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKeyBytes);
Key priKey = keyFactory.generatePrivate(pkcs8KeySpec);
KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
//用自己的私钥初始化keyAgreement
keyAgree.init(priKey);
keyAgree.doPhase(pubKey, true);
// 生成本地密钥
SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
return secretKey;
}
2.2.3 加密解密
/**
* 加密
* @param data 待加密数据
* @param publicKey 甲方公钥
* @param privateKey 乙方私钥
*/
public static String encrypt(byte[] data, String publicKey,String privateKey) throws Exception {
// 生成本地密钥
SecretKey secretKey = getSecretKey(publicKey, privateKey);
// 数据加密
Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return en.encode(cipher.doFinal(data));
}
/**
* 解密
*
* @param data 待解密数据
* @param publicKey 乙方公钥
* @param privateKey 乙方私钥
*/
public static String decrypt(byte[] data, String publicKey,String privateKey) throws Exception {
// 生成本地密钥
SecretKey secretKey = getSecretKey(publicKey, privateKey);
// 数据解密
Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return new String(cipher.doFinal(data));
}
2.2.4 结果验证
public static void main(String[] args)throws Exception {
// 生成甲方密钥对儿
Map aKeyMap = initKey();
String aPublicKey = getPublicKey(aKeyMap);
String aPrivateKey = getPrivateKey(aKeyMap);
System.err.println("甲方公钥:\r\n" + aPublicKey);
System.err.println("甲方私钥:\r\n" + aPrivateKey);
// 由甲方公钥产生本地密钥对儿
Map bKeyMap = initKey(aPublicKey);
String bPublicKey = getPublicKey(bKeyMap);
String bPrivateKey = getPrivateKey(bKeyMap);
System.err.println("乙方公钥:\r\n" + bPublicKey);
System.err.println("乙方私钥:\r\n" + bPrivateKey);
String aInput = "abc ";
System.err.println("原文: " + aInput);
// 由甲方公钥,乙方私钥构建密文
String aCode = encrypt(aInput.getBytes(), aPublicKey,bPrivateKey);
System.err.println("由甲方公钥,乙方私钥构建密文: \r\n" + aCode);
// 由乙方公钥,甲方私钥解密
String aDecode = decrypt(de.decodeBuffer(aCode), bPublicKey, aPrivateKey);
System.err.println("由乙方公钥,甲方私钥解密: \r\n" + aDecode);
System.err.println(" ===============反过来加密解密================== ");
String bInput = "def ";
System.err.println("原文: " + bInput);
// 由乙方公钥,甲方私钥构建密文
String bCode = encrypt(bInput.getBytes(), bPublicKey,aPrivateKey);
System.err.println("由乙方公钥,甲方私钥构建密文: \r\n" + bCode);
// 由甲方公钥,乙方私钥解密
String bDecode = decrypt(de.decodeBuffer(bCode), aPublicKey, bPrivateKey);
System.err.println("由甲方公钥,乙方私钥解密: \r\n" + bDecode);
}
3 DSA算法
3.1 定义
接下来我们介绍DSA
数字签名,非对称加密的另一种实现。
DSA
:DSA-Digital Signature Algorithm
是Schnorr
和ElGamal
签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。简单的说,这是一种更高级的验证方式,用作数字签名。不单单只有公钥
、私钥
,还有数字签名
。私钥加密生成数字签名,公钥验证数据及签名。如果数据和签名不匹配则认为验证失败!数字签名的作用就是校验数据在传输过程中不被修改。数字签名,是单向加密的升级
3.2 实际操作
用到的常量
public static final String ALGORITHM = "DSA";
/**
* 默认密钥字节数
*/
private static final int KEY_SIZE = 1024;
/**
* 默认种子
*/
private static final String DEFAULT_SEED = "0f22507a10bbddd07d8a3082122966e3";
private static final String PUBLIC_KEY = "DSAPublicKey";
private static final String PRIVATE_KEY = "DSAPrivateKey";
static BASE64Decoder de = new BASE64Decoder();
static BASE64Encoder en = new BASE64Encoder();
3.2.1 生成公私钥并获取
/**
* 生成密钥
*
* @param seed 种子
* @return 密钥对象
* @throws Exception
*/
public static Map initKey(String seed) throws Exception {
KeyPairGenerator keygen = KeyPairGenerator.getInstance(ALGORITHM);
// 初始化随机产生器
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(seed.getBytes());
keygen.initialize(KEY_SIZE, secureRandom);
KeyPair keys = keygen.genKeyPair();
DSAPublicKey publicKey = (DSAPublicKey) keys.getPublic();
DSAPrivateKey privateKey = (DSAPrivateKey) keys.getPrivate();
Map map = new HashMap(2);
map.put(PUBLIC_KEY, publicKey);
map.put(PRIVATE_KEY, privateKey);
return map;
}
/**
* 取得私钥
*/
public static String getPrivateKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return en.encode(key.getEncoded());
}
/**
* 取得公钥
*/
public static String getPublicKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return en.encode(key.getEncoded());
}
3.2.2 加签验签
3.2.2.1 私钥加签
/**
* 用私钥对信息生成数字签名
* @param data 加密数据
* @param privateKey 私钥
*/
public static String sign(byte[] data, String privateKey) throws Exception {
// 解密由base64编码的私钥
byte[] keyBytes = de.decodeBuffer(privateKey);
// 构造PKCS8EncodedKeySpec对象
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
// 取私钥匙对象
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 用私钥对信息生成数字签名
Signature signature = Signature.getInstance(keyFactory.getAlgorithm());
signature.initSign(priKey);
signature.update(data);
return en.encode(signature.sign());
}
3.2.2.1 公钥验签
/**
* 校验数字签名
*/
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
// 解密由base64编码的公钥
byte[] keyBytes = de.decodeBuffer(publicKey);
// 构造X509EncodedKeySpec对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
// ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
// 取公钥匙对象
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(keyFactory.getAlgorithm());
signature.initVerify(pubKey);
signature.update(data);
// 验证签名是否正常
return signature.verify(de.decodeBuffer(sign));
}
3.2.3 结果验证
public static void main(String[] args) throws Exception{
String inputStr = "abc";
byte[] data = inputStr.getBytes();
// 构建密钥
Map keyMap = initKey(DEFAULT_SEED);
// 获得密钥
String publicKey = getPublicKey(keyMap);
String privateKey = getPrivateKey(keyMap);
System.err.println("公钥:\r\n" + publicKey);
System.err.println("私钥:\r\n" + privateKey);
// 产生签名
String sign = sign(data, privateKey);
System.err.println("签名:\r\n" + sign);
// 验证签名
boolean status = verify(data, publicKey, sign);
System.err.println("状态:\r\n" + status);
}
4 ECC
4.1 定义
ECC
非对称加密算法最高级
ECC
-Elliptic Curves Cryptography
,椭圆曲线密码编码学,是目前已知的公钥体制中,对每比特所提供加密强度最高
的一种体制。在软件注册保护方面起到很大的作用,一般的序列号通常由该算法产生。
ECC
算法在jdk1.5
后加入支持,目前仅仅只能完成密钥的生成与解析。
如果想要获得ECC
算法实现,需要调用硬件完成加密/解密( ECC算法相当耗费资源
,如果单纯使用CPU
进行加密/解密,效率低下)
4.2 实际操作
注意
:Chipher
不支持EC
算法 ,以下代码仅供参考。Chipher、Signature、KeyPairGenerator、KeyAgreement、SecretKey
均不支持EC
算法。为了确保程序能够正常执行,使用了NullCipher
类,验证程序
其中的KeyFactory.getInstance("EC", "SunEC");
是参考ECKeyFactory
源码
如下代码用到的常量
public static final String ALGORITHM = "EC";
private static final String PUBLIC_KEY = "ECCPublicKey";
private static final String PRIVATE_KEY = "ECCPrivateKey";
static BASE64Decoder de = new BASE64Decoder();
static BASE64Encoder en = new BASE64Encoder();
4.2.1 生成公私钥并获取
/**
* 初始化密钥
*
* @return
* @throws Exception
*/
public static Map initKey() throws Exception {
BigInteger x1 = new BigInteger("2fe13c0537bbc11acaa07d793de4e6d5e5c94eee8", 16);
BigInteger x2 = new BigInteger("289070fb05d38ff58321f2e800536d538ccdaa3d9", 16);
ECPoint g = new ECPoint(x1, x2);
// the order of generator
BigInteger n = new BigInteger("5846006549323611672814741753598448348329118574063", 10);
// the cofactor
int h = 2;
int m = 163;
int[] ks = {7, 6, 3};
ECFieldF2m ecField = new ECFieldF2m(m, ks);
// y^2+xy=x^3+x^2+1
BigInteger a = new BigInteger("1", 2);
BigInteger b = new BigInteger("1", 2);
EllipticCurve ellipticCurve = new EllipticCurve(ecField, a, b);
ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, g, n, h);
// 公钥
ECPublicKey publicKey = new ECPublicKeyImpl(g, ecParameterSpec);
BigInteger s = new BigInteger("1234006549323611672814741753598448348329118574063", 10);
// 私钥
ECPrivateKey privateKey = new ECPrivateKeyImpl(s, ecParameterSpec);
Map keyMap = new HashMap(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 取得私钥
*/
public static String getPrivateKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return en.encode(key.getEncoded());
}
/**
* 取得公钥
*/
public static String getPublicKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return en.encode(key.getEncoded());
}
4.2.2 加密解密
/**
* 解密
* 用私钥解密
*/
public static String decrypt(byte[] data, String key) throws Exception {
// 对密钥解密
byte[] keyBytes = de.decodeBuffer(key);
// 取得私钥
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC", "SunEC");
ECPrivateKey priKey = (ECPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(priKey.getS(), priKey.getParams());
// 对数据解密
// Chipher不支持EC算法 未能实现
Cipher cipher = new NullCipher();
// Cipher.getInstance(ALGORITHM, keyFactory.getProvider());
cipher.init(Cipher.DECRYPT_MODE, priKey, ecPrivateKeySpec.getParams());
return new String(cipher.doFinal(data));
}
/**
* 加密
* 用公钥加密
*/
public static String encrypt(byte[] data, String privateKey) throws Exception {
// 对公钥解密
byte[] keyBytes = de.decodeBuffer(privateKey);
// 取得公钥
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC", "SunEC");
ECPublicKey pubKey = (ECPublicKey) keyFactory.generatePublic(x509KeySpec);
ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(pubKey.getW(), pubKey.getParams());
// 对数据加密
// TODO Chipher不支持EC算法 未能实现
Cipher cipher = new NullCipher();
// Cipher.getInstance(ALGORITHM, keyFactory.getProvider());
cipher.init(Cipher.ENCRYPT_MODE, pubKey, ecPublicKeySpec.getParams());
return en.encode(cipher.doFinal(data));
}
4.2.3 结果验证
public static void main(String[] args) throws Exception{
String inputStr = "abc";
byte[] data = inputStr.getBytes();
Map keyMap = initKey();
String publicKey = getPublicKey(keyMap);
String privateKey = getPrivateKey(keyMap);
System.err.println("公钥: \r\n" + publicKey);
System.err.println("私钥: \r\n" + privateKey);
String encodedData = encrypt(data, publicKey);
String decodedData = decrypt(de.decodeBuffer(encodedData), privateKey);
System.err.println("加密前: " + inputStr + "\n\n" + "解密后: " + decodedData);
}