如下文章字数大约2200字以及若干代码块,阅读时间需要45分钟左右。
数据安全是传输过程中必须要保证的底线。通常有2种方式来实现。通过第三方相关加解密设备或者根据JDK自身已实现的API来实现。
本文讲解的是利用JDK本身携带的API来实现加解密整套逻辑。
相关加解密名称包括:对称加密,非对称加密,签名,验签,摘要,数字信封。
【1】对称加密:
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。
常用算法:在 对称加密算法 中常用的算法有:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK、AES等。
【2】非对称加密:
对称加密算法在加密和解密时使用的是同一个秘钥;而非对称加密算法需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称 私钥 )。
【3】数字签名:
就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
数字签名是非对称密钥加密技术与数字摘要技术的应用。
私钥签名,公钥验签。
【4】摘要
它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。消息摘要采用单向Hash 函数将需加密的明文”摘要”成一串密文,这一串密文亦称为数字指纹(Finger Print)。它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是”真身”的”指纹”了。
息摘要,其实就是将需要摘要的数据作为参数,经过哈希函数(Hash)的计算,得到的散列值。
消息摘要算法包括MD(Message Digest,消息摘要算法)、SHA(Secure Hash Algorithm,安全散列算法)。
【5】以上概念统一一起叫做数字信封。
代码实现:
如下代码因为时间关系,并未进行相关参数整理,望理解。
看不明白的可以评论或私信。
如下代码为项目中能正常运行的。
public class JDKDigitalEnvelopeManager {
public static String KEY_DIGEST = “MD5”;//生成摘要类型
public static String SYM_KEY_ALGORITHM = “AES”; //对称加密算法类型
public static final int SYM_KEY_SIZE = 128;//要生成多少位。不同算法类型,具体值不一样。如果是AES,只需要修改这里即可128, 192或256
public static final String ASYM_KEY_ALGORITHM = “RSA”; //非对称加密
public static final String ASYM_CIPHER_ALGORITHM = “RSA”;
public static final String ASYM_PUBLIC_KEY = “publicKey”;
public static final String ASYM_PRIVATE_KEY = “privateKey”;
public static final int ASYM_KEY_SIZE = 1024;
/**
* 公钥,私钥文件地址
*/
public static String PUBLICKEY_PATH = “/home/tscp2/publicKey.txt”;
public static String PRIVATEKEY_PATH=”/home/tscp2/privateKey.txt”;
private KeyGenerator keyGenerator;
private SecretKey deskey;
private Cipher cipher;
private byte[] cipher byte ;
KeyPairGenerator keyPairGenerator;
KeyPair keyPair;
RSAPublicKey publicKey;
RSAPrivateKey privateKey;
/**
* 初始化
* @throws JseException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws TscpBaseException
*/
public void init() throws NoSuchAlgorithmException, NoSuchPaddingException{
keyGenerator = KeyGenerator. getInstance (SYM_KEY_ALGORITHM);
keyGenerator.init(SYM_KEY_SIZE);
deskey = keyGenerator.generateKey();
}
/**
* 对称密钥
* @throws JseException
*/
public byte[] getSymKey() {
cipherByte = deskey.getEncoded();//生成对称密钥
return cipherByte;
}
/**
* 释放
* @throws JseException
*/
public void close() {
}
/**
* 对称加密
*/
public byte[] symEncrypt(byte[] symKey ,byte[] inbyte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance(SYM_KEY_ALGORITHM);
SecretKeySpec sKeySpec = new SecretKeySpec(symKey,SYM_KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
byte[] byteData = cipher.doFinal(inbyte);
return byteData;
}
/**
* 对称解密
*/
public byte[] symDecrypt(byte[] symKey,byte[] encData) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
SecretKeySpec sKeySpec = new SecretKeySpec(symKey,SYM_KEY_ALGORITHM);
Cipher cipher = Cipher.getInstance(SYM_KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
byte[] byteData = cipher.doFinal(encData);
return byteData;
}
/**
* 得到非对称加密中公钥私钥对
*/
public Map<String,byte[]> getAsymKeyPairs() throws IOException, ClassNotFoundException, NoSuchAlgorithmException {
File filePublicKey = new File(PUBLICKEY_PATH);
File filePrivateKey = new File(PRIVATEKEY_PATH);
if ((filePublicKey != null) && (filePublicKey.exists()) && (filePrivateKey != null) && (filePrivateKey.exists())) {
FileInputStream fis = new FileInputStream(filePublicKey);
ObjectInputStream ois = new ObjectInputStream(fis);
RSAPublicKey publicKey = (RSAPublicKey)ois.readObject();
ois. close ();
fis.close();
fis = new FileInputStream(filePrivateKey);
ois = new ObjectInputStream(fis);
RSAPrivateKey privateKey = (RSAPrivateKey)ois.readObject();
ois.close();
fis.close();
Map<String,byte[]> keyMap = new HashMap<String,byte[]>();
keyMap.put(“publicKey”, publicKey.getEncoded());
keyMap.put(“privateKey”, privateKey.getEncoded());
return keyMap;
}
initKeyPairGenerator();
Map<String,byte[]> keyMap = new HashMap<String,byte[]>();
keyMap.put(“publicKey”, publicKey.getEncoded());
keyMap.put(“privateKey”, privateKey.getEncoded());
File file = new File(PUBLICKEY_PATH);
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(publicKey);
oos.flush();
oos.close();
fos.close();
file = new File(PRIVATEKEY_PATH);
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(privateKey);
oos.flush();
oos.close();
fos.close();
return keyMap;
}
private void initKeyPairGenerator() throws NoSuchAlgorithmException {
keyPairGenerator = KeyPairGenerator.getInstance(ASYM_KEY_ALGORITHM);
keyPairGenerator.initialize(ASYM_KEY_SIZE);
keyPair = keyPairGenerator.generateKeyPair();
publicKey = (RSAPublicKey)keyPair.getPublic();
privateKey = (RSAPrivateKey)keyPair.getPrivate();
}
/**
* 非对称加密
* @throws JseException
*/
public String asymEncrypt(byte[] keyByte,String data) {
PublicKey publicKey = restorePublicKey(keyByte);
String encodedText = asymEncrypt(publicKey, data);
return encodedText;
}
/**
* 非对称解密
* @throws JseException
*/
public String asymDecrypt(byte[] keyByte,String data) {
PrivateKey privateKey = restorePrivateKey(keyByte);
String asymData = asymDecrypt(privateKey, data);
return asymData;
}
public static String asymDecrypt(PrivateKey key, String encodedText){
try{
Cipher cipher = Cipher.getInstance(ASYM_CIPHER_ALGORITHM);
cipher.init(2, key);
int key_len = 128;
byte[] bytes = encodedText.getBytes();
byte[] bcd = ascii _To_BCD(bytes, bytes. length );
System.err.println(bcd.length);
String ming = “”;
byte[][] arrays = splitArray(bcd, key_len);
for (byte[] arr : arrays) {
ming = ming + new String(cipher.doFinal(arr));
}
return ming;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private String asymEncrypt(PublicKey key, String plainText) {
try{
Cipher cipher = Cipher.getInstance(ASYM_CIPHER_ALGORITHM);
cipher.init(1, key);
int MaxBlockSize = 128;
String[] datas = splitString(plainText, MaxBlockSize – 11);
String mi = “”;
for (String s : datas) {
mi = mi + bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 生成摘要
* @param inbyte
* @return
* @throws JseException
* @throws NoSuchAlgorithmException
*/
public byte[] digest(byte[] inbyte) throws NoSuchAlgorithmException {
MessageDigest md5 = MessageDigest.getInstance(KEY_DIGEST);
byte[] digestByte = md5.digest(inbyte);
return digestByte;
}
public static byte[][] splitArray(byte[] data, int len){
int x = data.length / len;
int y = data.length % len;
int z = 0;
if (y != 0) {
z = 1;
}
byte[][] arrays = new byte[x + z][];
for (int i = 0; i < x + z; i++) {
byte[] arr = new byte[len];
if ((i == x + z – 1) && (y != 0))
System.arraycopy(data, i * len, arr, 0, y);
else {
System.arraycopy(data, i * len, arr, 0, len);
}
arrays[i] = arr;
}
return arrays;
}
public static PrivateKey restorePrivateKey(byte[] keyBytes){
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec( keyBytes);
try {
KeyFactory factory = KeyFactory.getInstance(“RSA”);
return factory.generatePrivate(pkcs8EncodedKeySpec);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
byte[] bcd = new byte[asc_len / 2];
int j = 0;
for (int i = 0; i < (asc_len + 1) / 2; i++) {
bcd[i] = asc_to_bcd(ascii[(j++)]);
bcd[i] = ((byte)((j >= asc_len ? 0 : asc_to_bcd(ascii[(j++)])) + (bcd[i] << 4)));
}
return bcd;
}
public static byte asc_to_bcd(byte asc){
byte bcd;
if ((asc >= 48) && (asc <= 57)) {
bcd = (byte)(asc – 48);
}else{
if ((asc >= 65) && (asc <= 70)) {
bcd = (byte)(asc – 65 + 10);
}else{
if ((asc >= 97) && (asc <= 102)){
bcd = (byte)(asc – 97 + 10);
}else{
bcd = (byte)(asc – 48);
}
}
}
return bcd;
}
public static String bcd2Str(byte[] bytes) {
char [] temp = new char[bytes.length * 2];
for (int i = 0; i < bytes.length; i++) {
char val = (char)((bytes[i] & 0xF0) >> 4 & 0xF);
temp[(i * 2)] = ((char)(val > ‘t’ ? val + ‘A’ – 10 : val + ‘0’));
val = (char)(bytes[i] & 0xF);
temp[(i * 2 + 1)] = ((char)(val > ‘t’ ? val + ‘A’ – 10 : val + ‘0’));
}
return new String(temp);
}
public static String[] splitString(String string, int len) {
int x = string.length() / len;
int y = string.length() % len;
int z = 0;
if (y != 0) {
z = 1;
}
String[] strings = new String[x + z];
String str = “”;
for (int i = 0; i < x + z; i++) {
if ((i == x + z – 1) && (y != 0))
str = string.substring(i * len, i * len + y);
else {
str = string.substring(i * len, i * len + len);
}
strings[i] = str;
}
return strings;
}
private PublicKey restorePublicKey(byte[] keyBytes) {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
try{
KeyFactory factory = KeyFactory.getInstance(ASYM_KEY_ALGORITHM);
return factory.generatePublic(x509EncodedKeySpec);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* 签名
*/
public byte[] sign(byte[] keyByte,byte[] inbyte) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException{
initKeyPairGenerator();
PKCS8EncodedKeySpec pkcs8EncodedKeySpec=new PKCS8EncodedKeySpec(keyByte);
KeyFactory keyFactory=KeyFactory.getInstance(ASYM_KEY_ALGORITHM);
PrivateKey privateKey=keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature=Signature.getInstance(“MD5withRSA”);
signature.initSign(privateKey);
signature.update(inbyte);
byte[] result=signature.sign();
return result;
}
/**
* 验证签名
*
*/
public boolean verifySign(byte[] keyByte,byte[] inbyte,byte[] sign) throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException{
initKeyPairGenerator();
X509EncodedKeySpec x509EncodedKeySpec=new X509EncodedKeySpec(keyByte);
KeyFactory keyFactory=KeyFactory.getInstance(ASYM_KEY_ALGORITHM);
PublicKey publicKey=keyFactory.generatePublic(x509EncodedKeySpec);
Signature signature=Signature.getInstance(“MD5withRSA”);
signature.initVerify(publicKey);
signature.update(inbyte);
boolean bool=signature.verify(sign);
return bool;
}
}
下篇预告 :想聊一聊关于大数据相关方面的内容,准备下一篇讲讲Hbase的相关内容。
如果有感兴趣或者疑惑的知识点,可以评论或者私信我,我会准备相关内容,推出对应的文章。
已上内容,纯属一家之言,因本人能力一般,见识有限,如有问题,请不吝指正,感谢。
相关技术内容会持续更新,大家可随时交流,欢迎关注本头条号。