有时候访问群的时候,有一个大神用某个算法加密了一句话,在群里聊天,我真的很羡慕。 因为我不能理解_
一. DES加密算法的简单原理:
很抱歉画得不好,但更基础的原理我暂时不深挖。 密码学本来就是一个大洞,越挖越深。 我不推荐深入学习,因为我不是相关专业。
别胡说,上码:
import Java.security.invalidkeyexception;
import Java.security.nosuchalgorithmexception;
import javax.crypto.badpaddingexception;
import javax.crypto.Cipher;
import javax.crypto.illegalblocksizeexception;
import javax.crypto.nosuchpaddingexception;
import javax.crypto.spec.secret key spec;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.Random;
公共类测试des {
publicstaticvoidmain (字符串[ ] args ) {
String plainText='今天吃饭了吗? 如果吃了的话,就可以了。 那证明了你爱我!' ; //明文
//值得注意的是,用现在的getKey ()方法来看
//原始加密密钥的长度越大,越可能生成不同的密文(length个密文线性地增加) )。
//设密文的数量为y,原加密密钥的长度为x,则y=x
如果rawKey中只有一个字符占一个字节,则只生成一个密文
//(经我多次尝试,原始加密密钥“01”有两个字节,但似乎也只生成一个密文。 理由不明)
//我写的这个getKey ()确实是鸡肋) )。
String rawKey='ldl123789654 '; //原始密钥
//指定随机正整数作为加密密钥字节数组中的第一个填充位置
int randomIndex=new Random ().nextint (rawkey.getbytes ) ).length );
string cipher text=test des.desencrypt (plaintext,rawKey,randomIndex );
stringtoplaintext=test des.des decrypt (cipher text,rawKey,randomIndex );
System.out.println (密文: ' cipherText );
System.out.println ('明文: ' toPlainText );
}
publicstaticstringdesencrypt (string plaintext,String rawKey,int randomIndex ) {
String cipherText=null;
try {
//这里采用SecretKeySpec key是想定制钥匙的生产规则
secretkeyspeckey=test des.getkey (rawkey,randomIndex );
//1,获取加密算法的工具类对象
cipher cipher=cipher.getinstance (' des );
//2、初始化加密算法的工具类对象
//opmode是操作模式,加密/解密
//key是转换原始加密密钥的加密密钥SecretKeySpec对象
cipher.init (cipher.encrypt _ mode,key;
//3、用密码算法工具类对象加密明文
byte [ ] do final=cipher.do final (plaintext.getbytes ();
//4、base64编解码器解决编解码后乱码问题的同时,发挥再加密的效果
encoder encoder=base64.get encoder (;
cipher text=encoder.encode tostring (do final );
} catch (nosuchalgorithmexception )|nosuchpaddingexception|illegalblocksizeexception|badpaddingexception
{e.printStackTrace();
}
return cipherText;
}
public static String desDecrypt(String cipherText, String rawKey, int randomIndex) {
String plainText = null;
try {
SecretKeySpec key = TestDES.getKey(rawKey, randomIndex);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
Decoder deCoder = Base64.getDecoder();
byte[] deCodeBytes = deCoder.decode(cipherText);
byte[] doFinal = cipher.doFinal(deCodeBytes);
plainText = new String(doFinal);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
return plainText;
}
private static SecretKeySpec getKey(String rawKey, int randomIndex) {
//将用户输入任意长度的原始密匙转换为8个字节的原始密匙
byte[] buffer = new byte[8];
byte[] rawKeyBytes = rawKey.getBytes();
//进行遍历,从一个随机的位置开始循环取值填充到buffer数组里
//若小于8则剩余元素使用byte 0填充,若大于8只取前8个字节
//这只是一种简单的处理方式,当然还有更复杂的处理方式
//for循环结束后可能产生的加密密匙数为rawKeyBytes.length
//即可能产生rawKeyBytes.length个密文(等于可能产生的加密密匙的数目)
for (int i = 0; i < 8 && i < rawKeyBytes.length; i++) {
if (randomIndex >= rawKeyBytes.length) {
randomIndex = 0;
}
buffer[i] = rawKeyBytes[randomIndex++];
}
//DES密匙只支持64位即8个字节的大小,多一个少一个都不行
return new SecretKeySpec(buffer, "DES");
}
}
碰到的问题:在对 byte[] 数组操作(如调用字符串的 getBytes() 方法或者调用算法工具类对象的 doFinal(byte[] arr) 方法)的过程中,若不指定编解码方式,则采用系统默认的编解码方式,我的是中文 win10 系统,默认采用 GBK 编解码。由于 DES 加密算法过于复杂导致最后加密转换后的 byte[] 数组里的字节,很可能在GBK码表上找不到对应的字符(字节丢失),所以在解码时会产生乱码。
解决思路:找一个码表,在解码后,无论是怎样的二进制字节,都能找到对应的字符。
这样的码表就是 Base64 码表。
Base64码表编解码简要原理:
将会出现的三种情况(只有三种)
1、当字符串所占字节数 % 3 = 0 时,依次取6位(2的6次方,刚好对应Base64码表上的64个字符),刚好拆分完。
如字符串 “ABC” 对应的二进制:
01000001 01000010 01000011
010000 | 01 0100 | 0010 01 | 000011
Q | U | J | D
再将分割出来的二进制数转为十进制数,对照Base64码表可得出: “ABC” --> QUJD。
2、当字符串所占字节数 % 3 = 1 时,依次取 6 位,将会剩下 4 位,缺少的 2 位用 0 补足。
如字符串 “ce” 对应的二进制:
01100011 01100101
011000 | 11 0110 | 0101(00) ( )表示补足的位
Y | 2 | U
对照Base64码表: “ce” --> Y2U=(一个=表示补了00)
3、当字符串所占字节数 % 3 = 2 时,依次取 6 位,将会剩下 2 位,缺少的 4 位用 0 补足。
如字符串“{”对应的二进制:
01111011
011110 | 11(0000) ( )表示补足的位
e | w
对照Base64码表: “{” --> ew==(==表示补了0000)。
好了,该介绍的我都差不多介绍完了,只为了写一个小小的DES加密解密程序,得掌握一些有趣但是略微“偏门”的知识点。天啊,才反应过来,我又钻了一个晚上的牛角尖!
溜了溜了,最后再乱入一个迷你的小蘑菇加密解密的源码:
public class TestCaesarCipher {
public static void main(String[] args) {
String plainText = "Alei&Ali1314@0101_*";
int key = 3;
String cipherText = TestCaesarCipher.encrypt(plainText, key);
System.out.println("密文:" + cipherText);
String toPlainText = TestCaesarCipher.decrypt(cipherText, key);
System.out.println("明文:" + toPlainText);
}
public static String encrypt(String plainText, int key) {
char[] tempCharArr = plainText.toCharArray();
for (int i = 0; i < tempCharArr.length; i++) {
tempCharArr[i] += key;
}
return new String(tempCharArr);
}
public static String decrypt(String cipherText, int key) {
char[] tempCharArr = cipherText.toCharArray();
for (int i = 0; i < tempCharArr.length; i++) {
tempCharArr[i] -= key;
}
return new String(tempCharArr);
}
}