服务端生成公钥与私钥,保存。
客户端在请求到登录页面后,随机生成一字符串。
后此随机字符串作为密钥加密密码,再用从服务端获取到的公钥加密生成的随机字符串
将此两段密文传入服务端,服务端用私钥解出随机字符串,再用此私钥解出加密的密文。这其中有一个关键是解决服务端的公钥,传入客户端,客户端用此公钥加密字符串后,后又能在服务端用私钥解出。
步骤:
服务端的RSA Java实现:
/***
*/
package com.sunsoft.struts.util
import java.io.ByteArrayOutputStream
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.math.BigInteger
import java.security.KeyFactory
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.NoSuchAlgorithmException
import java.security.PrivateKey
import java.security.PublicKey
import java.security.SecureRandom
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.InvalidKeySpecException
import java.security.spec.RSAPrivateKeySpec
import java.security.spec.RSAPublicKeySpec
import javax.crypto.Cipher
/**
* RSA 工具类。提供加密,解密,生成密钥对等方法。
* 需要到
下载bcprov-jdk14-123.jar。
*
*/
public class RSAUtil {
/**
* * 生成密钥对 *
*
* @return KeyPair *
* @throws EncryptException
*/
public static KeyPair generateKeyPair() throws Exception {
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider())
final int KEY_SIZE = 1024// 没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低
keyPairGen.initialize(KEY_SIZE, new SecureRandom())
KeyPair keyPair = keyPairGen.generateKeyPair()
saveKeyPair(keyPair)
return keyPair
} catch (Exception e) {
throw new Exception(e.getMessage())
}
}
public static KeyPair getKeyPair()throws Exception{
FileInputStream fis = new FileInputStream("C:/RSAKey.txt")
ObjectInputStream oos = new ObjectInputStream(fis)
KeyPair kp= (KeyPair) oos.readObject()
oos.close()
fis.close()
return kp
}
public static void saveKeyPair(KeyPair kp)throws Exception{
FileOutputStream fos = new FileOutputStream("C:/RSAKey.txt")
ObjectOutputStream oos = new ObjectOutputStream(fos)
//生成密钥
oos.writeObject(kp)
oos.close()
fos.close()
}
/**
* * 生成公钥 *
*
* @param modulus *
* @param publicExponent *
* @return RSAPublicKey *
* @throws Exception
*/
public static RSAPublicKey generateRSAPublicKey(byte[] modulus,
byte[] publicExponent) throws Exception {
KeyFactory keyFac = null
try {
keyFac = KeyFactory.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider())
} catch (NoSuchAlgorithmException ex) {
throw new Exception(ex.getMessage())
}
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
modulus), new BigInteger(publicExponent))
try {
return (RSAPublicKey) keyFac.generatePublic(pubKeySpec)
} catch (InvalidKeySpecException ex) {
throw new Exception(ex.getMessage())
}
}
/**
* * 生成私钥 *
*
* @param modulus *
* @param privateExponent *
* @return RSAPrivateKey *
* @throws Exception
*/
public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
byte[] privateExponent) throws Exception {
KeyFactory keyFac = null
try {
keyFac = KeyFactory.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider())
} catch (NoSuchAlgorithmException ex) {
throw new Exception(ex.getMessage())
}
RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
modulus), new BigInteger(privateExponent))
try {
return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec)
} catch (InvalidKeySpecException ex) {
throw new Exception(ex.getMessage())
}
}
/**
* * 加密 *
*
* @param key
* 加密的密钥 *
* @param data
* 待加密的明文数据 *
* @return 加密后的数据 *
* @throws Exception
*/
public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
try {
Cipher cipher = Cipher.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider())
cipher.init(Cipher.ENCRYPT_MODE, pk)
int blockSize = cipher.getBlockSize()// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
// 加密块大小为127
// byte,加密后为128个byte因此共有2个加密块,第一个127
// byte第二个为1个byte
int outputSize = cipher.getOutputSize(data.length)// 获得加密块加密后块大小
int leavedSize = data.length % blockSize
int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
: data.length / blockSize
byte[] raw = new byte[outputSize * blocksSize]
int i = 0
while (data.length - i * blockSize > 0) {
if (data.length - i * blockSize > blockSize)
cipher.doFinal(data, i * blockSize, blockSize, raw, i
* outputSize)
else
cipher.doFinal(data, i * blockSize, data.length - i
* blockSize, raw, i * outputSize)
// 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到
// ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了
// OutputSize所以只好用dofinal方法。
i++
}
return raw
} catch (Exception e) {
throw new Exception(e.getMessage())
}
}
/**
* * 解密 *
*
* @param key
* 解密的密钥 *
* @param raw
* 已经加密的数据 *
* @return 解密后的明文 *
* @throws Exception
*/
public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
try {
Cipher cipher = Cipher.getInstance("RSA",
new org.bouncycastle.jce.provider.BouncyCastleProvider())
cipher.init(cipher.DECRYPT_MODE, pk)
int blockSize = cipher.getBlockSize()
ByteArrayOutputStream bout = new ByteArrayOutputStream(64)
int j = 0
while (raw.length - j * blockSize > 0) {
bout.write(cipher.doFinal(raw, j * blockSize, blockSize))
j++
}
return bout.toByteArray()
} catch (Exception e) {
throw new Exception(e.getMessage())
}
}
/**
* * *
*
* @param args *
* @throws Exception
*/
public static void main(String[] args) throws Exception {
RSAPublicKey rsap = (RSAPublicKey) RSAUtil.generateKeyPair().getPublic()
String test = "hello world"
byte[] en_test = encrypt(getKeyPair().getPublic(),test.getBytes())
byte[] de_test = decrypt(getKeyPair().getPrivate(),en_test)
System.out.println(new String(de_test))
}
}
测试页面IndexAction.java:
/** Generated by MyEclipse Struts
* Template path: templates/java/JavaClass.vtl
*/
package com.sunsoft.struts.action
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.apache.struts.action.Action
import org.apache.struts.action.ActionForm
import org.apache.struts.action.ActionForward
import org.apache.struts.action.ActionMapping
import com.sunsoft.struts.util.RSAUtil
/**
* MyEclipse Struts
* Creation date: 06-28-2008
*
* XDoclet definition:
* @struts.action validate="true"
*/
public class IndexAction extends Action {
/*
* Generated Methods
*/
/**
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)throws Exception {
RSAPublicKey rsap = (RSAPublicKey) RSAUtil.getKeyPair().getPublic()
String module = rsap.getModulus().toString(16)
String empoent = rsap.getPublicExponent().toString(16)
System.out.println("module")
System.out.println(module)
System.out.println("empoent")
System.out.println(empoent)
request.setAttribute("m", module)
request.setAttribute("e", empoent)
return mapping.findForward("login")
}
}
通过此action进入登录页面,并传入公钥的 Modulus 与PublicExponent的hex编码形式。
题主是否想询问“jsrsasign不支持公钥解密的解决办法”?1、首先进入jsencrypt/lib/lib/jsbn/rsa.js。
2、然后在rsa.js文件中,第207行附近的RSAKey.prototype.decrypt方法中,将 this.doPrivate(c) 改为 this.doPublic(c)。
3、同样在rsa.js文件中,找到第310行附近的pkcs1unpad2方法,并将这三行代码注释。
4、最后保存修改后的rsa.js文件,就实现了jsencrypt使用公钥解密数据的功能。
加密在我们前端的开发中也是经常遇见的。本文只把我们常用的加密方法进行总结。不去纠结加密的具体实现方式(密码学,太庞大了)。
常见的加密算法基本分为这几类,
RSA加密:RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。(这才是正经的加密算法)
非对称加密算法:非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法
DES算法的入口参数有三个:Key、Data、Mode。其中Key为7个字节共56位,是DES算法的工作密钥;Data为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。
AES这个标准用来替代原先的DES
DES/AES我们合并在一起介绍其用法和特点
Base64是一种用64个字符来表示任意二进制数据的方法。base64是一种编码方式而不是加密算法。只是看上去像是加密而已(吓唬人)。