密码算法
因考虑到算法所需的性能较小,因此将密码算法功能集成于前端,从而减少后台服务器的压力,后台主要实现了密码数据的管理功能。
密码管理
1.除了在加解密对应页面实现保存密码,密码管理模块中也可以。
2.可以查询当前用户所保存的密码,且可进行增删改查操作。
3.可以对保存的所有密码数据进行下载。
4.使用代码生成构建,提高了开发效率
这里就展示主要的业务层代码,其余代码大家可以前往我代码的源码中查看
package com.ruoyi.ai.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import org.springframework.stereotype.Service;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.ai.domain.bo.AiPwdBo;
import com.ruoyi.ai.domain.vo.AiPwdVo;
import com.ruoyi.ai.domain.AiPwd;
import com.ruoyi.ai.mapper.AiPwdMapper;
import com.ruoyi.ai.service.IAiPwdService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 密码管理Service业务层处理
*
* @author 何翔
* @date 2022-04-30
*/
@Service
public class AiPwdServiceImpl extends ServicePlusImpl<AiPwdMapper, AiPwd, AiPwdVo> implements IAiPwdService {
@Override
public AiPwdVo queryById(Long id){
return getVoById(id);
}
@Override
public TableDataInfo<AiPwdVo> queryPageList(AiPwdBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<AiPwd> lqw = buildQueryWrapper(bo);
QueryWrapper<AiPwd> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id",SecurityUtils.getUserId());
Page<AiPwdVo> result = pageVo(pageQuery.build(), queryWrapper);
return TableDataInfo.build(result);
}
@Override
public List<AiPwdVo> queryList(AiPwdBo bo) {
LambdaQueryWrapper<AiPwd> lqw = buildQueryWrapper(bo);
QueryWrapper<AiPwd> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id",SecurityUtils.getUserId());
return listVo(queryWrapper);
}
private LambdaQueryWrapper<AiPwd> buildQueryWrapper(AiPwdBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<AiPwd> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getText()), AiPwd::getText, bo.getText());
lqw.like(StringUtils.isNotBlank(bo.getKeyWord()), AiPwd::getKeyWord, bo.getKeyWord());
lqw.like(StringUtils.isNotBlank(bo.getCiphertext()), AiPwd::getCiphertext, bo.getCiphertext());
lqw.like(StringUtils.isNotBlank(bo.getRemark()), AiPwd::getRemark, bo.getRemark());
lqw.eq(bo.getCreateTime() != null, AiPwd::getCreateTime, bo.getCreateTime());
return lqw;
}
@Override
public Boolean insertByBo(AiPwdBo bo) {
AiPwd add = BeanUtil.toBean(bo, AiPwd.class);
add.setUserId(SecurityUtils.getUserId());
System.out.println(add);
validEntityBeforeSave(add);
boolean flag = save(add);
if (flag) {
bo.setId(add.getId());
}
return flag;
}
@Override
public Boolean updateByBo(AiPwdBo bo) {
AiPwd update = BeanUtil.toBean(bo, AiPwd.class);
validEntityBeforeSave(update);
return updateById(update);
}
/**
* 保存前的数据校验
*
* @param entity 实体类数据
*/
private void validEntityBeforeSave(AiPwd entity){
//TODO 做一些数据校验,如唯一约束
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return removeByIds(ids);
}
}
核心算法
本项目的密码算法功能是基于前端版,前端版算法源码链接:https://github.com/sytelus/CryptoJS](https://github.com/sytelus/CryptoJS))
算法简介
由于本项目已经再前端集成了密码算法,因此如果有想改成后端完成的话,也非常简单,直接调用接口返回密码加密数据即可。接下来就给大家介绍一下用后端写的话,代码是怎么样的。
DES
DES(Data Encryption Standard,数据加密标准)算法是对称加密算法领域中的典型算法,DES算法秘钥较短,以现在计算机的计算能力,DES算法加密的数据在24小时内可能被破解。所以DES算法已经被淘汰,建议使用AES算法,不过这里还是简单了解下。
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class DesUtil {
private static Key key;
private static String KEY_STR="myKey";
private static String CHARSETNAME="UTF-8";
private static String ALGORITHM="DES";
static {
try {
//生成DES算法对象
KeyGenerator generator=KeyGenerator.getInstance(ALGORITHM);
//运用SHA1安全策略
SecureRandom secureRandom=SecureRandom.getInstance("SHA1PRNG");
//设置上密钥种子
secureRandom.setSeed(KEY_STR.getBytes());
//初始化基于SHA1的算法对象
generator.init(secureRandom);
//生成密钥对象
key=generator.generateKey();
generator=null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/***
* 获取加密的信息
* @param str
* @return
*/
public static String getEncryptString(String str) {
//基于BASE64编码,接收byte[]并转换成String
BASE64Encoder encoder = new BASE64Encoder();
try {
//按utf8编码
byte[] bytes = str.getBytes(CHARSETNAME);
//获取加密对象
Cipher cipher = Cipher.getInstance(ALGORITHM);
//初始化密码信息
cipher.init(Cipher.ENCRYPT_MODE, key);
//加密
byte[] doFinal = cipher.doFinal(bytes);
//byte[]to encode好的String 并返回
return encoder.encode(doFinal);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/***
* 获取解密之后的信息
* @param str
* @return
*/
public static String getDecryptString(String str) {
BASE64Decoder decoder = new BASE64Decoder();
try {
//将字符串decode成byte[]
byte[] bytes = decoder.decodeBuffer(str);
//获取解密对象
Cipher cipher = Cipher.getInstance(ALGORITHM);
//初始化解密信息
cipher.init(Cipher.DECRYPT_MODE, key);
//解密
byte[] doFial = cipher.doFinal(bytes);
return new String(doFial, CHARSETNAME);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
AES
AES(AdvancedEncryption Standard,高级数据加密标准)算法支持128位、192位和256位的秘钥长度,加密速度比DES和DESede都快,至今还没有被破解的报道。经过验证,目前采用的AES算法能够有效抵御已知的针对DES算法的所有攻击方法,如部分差分攻击、相关秘钥攻击等。AES算法因秘钥建立时间短、灵敏性好、内存需求低等优点,在各个领域得到广泛的研究与应用。
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AESUtil {
public static final String algorithm = "AES";
// AES/CBC/NOPaddin
// AES 默认模式
// 使用CBC模式, 在初始化Cipher对象时, 需要增加参数, 初始化向量IV : IvParameterSpec iv = new
// IvParameterSpec(key.getBytes());
// NOPadding: 使用NOPadding模式时, 原文长度必须是8byte的整数倍
public static final String transformation = "AES/CBC/NOPadding";
public static final String key = "1234567812345678";
/***
* 加密
* @param original 需要加密的参数(注意必须是16位)
* @return
* @throws Exception
*/
public static String encryptByAES(String original) throws Exception {
// 获取Cipher
Cipher cipher = Cipher.getInstance(transformation);
// 生成密钥
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), algorithm);
// 指定模式(加密)和密钥
// 创建初始化向量
IvParameterSpec iv = new IvParameterSpec(key.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
// cipher.init(Cipher.ENCRYPT_MODE, keySpec);
// 加密
byte[] bytes = cipher.doFinal(original.getBytes());
return Base64Util.encryptBASE64(bytes);
}
/**
* 解密
* @param encrypted 需要解密的参数
* @return
* @throws Exception
*/
public static String decryptByAES(String encrypted) throws Exception {
// 获取Cipher
Cipher cipher = Cipher.getInstance(transformation);
// 生成密钥
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), algorithm);
// 指定模式(解密)和密钥
// 创建初始化向量
IvParameterSpec iv = new IvParameterSpec(key.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
// cipher.init(Cipher.DECRYPT_MODE, keySpec);
// 解密
byte[] bytes = cipher.doFinal(Base64Util.decryBASE64(encrypted));
return new String(bytes);
}
}5.HMAC(Hash Message Authentication Code,散列消息鉴别码)
TripleDES
3DES又称TripleDES,是DES加密算法的一种模式,它使用2条不同的56位的密钥对数据进行三次加密。数据加密标准(DES)是美国的一种由来已久的加密标准,它使用对称密钥加密法,并于1981年被ANSI组织规范为ANSIX.3.92。DES使用56位密钥和密码块的方法,而在密码块的方法中,文本被分成64位大小的文本块然后再进行加密。比起最初的DES,3DES更为安全。3DES(即TripleDES)是DES向AES过渡的加密算法,它使用3条56位的密钥对数据进行三次加密。是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。比起最初的DES,3DES更为安全。TripleDES属于对称加密算法,加解密使用同一个秘钥。
package com.topnet.utils;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Scanner;
public class TripleDES {
private static final String Algorithm="DESede";
public static void main(String[] args) throws Exception
{
System.out.println("请输入明文:");
Scanner in=new Scanner(System.in);
String clearText=in.nextLine();
System.out.println("请输入24字节的密钥(每输入一个字符代表一个字节):");
Scanner in1=new Scanner(System.in);
String originKey=in1.nextLine();
String cipherText = desEncript(clearText, originKey);
System.out.println("通过3DES加密后的结果是:");
System.out.println(cipherText);
String clearText1=desDecript(cipherText,originKey);
System.out.println("解密结果是:\n"+clearText1);
}
static {
if (Security.getProvider("BC") == null) {
Security.addProvider(new BouncyCastleProvider());
} else {
Security.removeProvider("BC");
Security.addProvider(new BouncyCastleProvider());
}
}
/**
* 加密算法
* @param clearText
* @param originKey
* @return
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String desEncript(String clearText, String originKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException
{
Cipher cipher= null; /*提供加密的方式:DES*/
try {
cipher = Cipher.getInstance("DESede/ECB/PKCS7Padding", "BC");
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
SecretKeySpec key=getKey(originKey); /*对密钥进行操作,产生16个48位长的子密钥*/
cipher.init(Cipher.ENCRYPT_MODE,key); /*初始化cipher,选定模式,这里为加密模式,并同时传入密钥*/
byte[] doFinal=cipher.doFinal(clearText.getBytes()); /*开始加密操作*/
String encode= Base64.encode(doFinal); /*对加密后的数据按照Base64进行编码*/
return encode;
}
/**
* 解密算法
* @param cipherText
* @param originKey
* @return
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static String desDecript(String cipherText, String originKey) throws BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException
{
Cipher cipher= null; /*初始化解密方式*/
try {
cipher = Cipher.getInstance("DESede/ECB/PKCS7Padding", "BC");
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
Key key=getKey(originKey); /*获取密钥*/
cipher.init(Cipher.DECRYPT_MODE,key); /*初始化操作方式*/
byte[] decode=Base64.decode(cipherText); /*按照Base64解码*/
byte[] doFinal=cipher.doFinal(decode); /*执行解码操作*/
return new String(doFinal); /*转换成相应字符串并返回*/
}
/**
* 获取密钥算法
* @param originKey
* @return
*/
public static SecretKeySpec getKey(String originKey)
{
byte[] buffer=new byte[24];
byte[] originBytes=originKey.getBytes();
/**
* 防止输入的密钥长度超过192位
*/
for(int i=0;i<24&&i<originBytes.length;i++)
{
buffer[i]=originBytes[i]; /*如果originBytes不足8,buffer剩余的补零*/
}
SecretKeySpec key=new SecretKeySpec(buffer,Algorithm); /*第一个参数是密钥字节数组,第二个参数是加密方式*/
return key; /*返回操作之后得到的密钥*/
}
}
RC4
RC4于1987年提出,和DES算法一样,是一种对称加密算法,也就是说使用的密钥为单钥(或称为私钥)。但不同于DES的是,RC4不是对明文进行分组处理,而是字节流的方式依次加密明文中的每一个字节,解密的时候也是依次对密文中的每一个字节进行解密。
RC4算法的特点是算法简单,运行速度快,而且密钥长度是可变的,可变范围为1-256字节(8-2048比特),在如今技术支持的前提下,当密钥长度为128比特时,用暴力法搜索密钥已经不太可行,所以可以预见RC4的密钥范围任然可以在今后相当长的时间里抵御暴力搜索密钥的攻击。实际上,如今也没有找到对于128bit密钥长度的RC4加密算法的有效攻击方法。
import java.util.Scanner;
public class RC4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
codebooksc c1 = new codebooksc();
Scanner sc =new Scanner(System.in);
System.out.println("密钥:");
String k1 = sc.next();
int m = k1.length();//密钥长度
char K[] = new char[m];//密钥空间
for(int i=0;i<m;i++)
{
K[i] = k1.charAt(i);
}
Integer S[] = new Integer [256];//S表
Integer T[] = new Integer [256];//T表
c1.permutateS(S, T, K);//S表排序
System.out.println("明文:");
String p = sc.next();
int n = p.length();
char P[] = new char[n];//明文空间;
for(int i=0;i<n;i++) {
P[i]=p.charAt(i);
}
char keys[] = new char[n];//密钥流;
c1.GenerateKeys(S, n,keys);//产生密钥流
char C[] = new char[n];//密文空间;
System.out.println();
String ccc = c1.encrypt(keys, n, P,C);
System.out.println("密文:");
System.out.print(ccc);
for(int i=0;i<n;i++)
{
C[i] = ccc.charAt(i);
}
System.out.println();
String pp =c1.decrypt( keys, n, C);
System.out.println("明文是:");
System.out.println(pp);
}
}
class codebooksc{
public void permutateS(Integer S[],Integer T[],char K[]) {//初始排列S表;
for(int i=0;i<256;i++) {
S[i] = i;
}
int t[] = new int[256];
for(int i=0;i<256;i++) {
t[i] = K[i%K.length ];
T[i] = t[i];
}
int j=0;
for(int i=0;i<255;i++)
{
j = (j+S[i]+T[i])%256;
int temp; //交换S【i】与S【j】;
temp = S[i];
S[i] = S[j];
S[j] = temp;
}
}
public void GenerateKeys(Integer S[],int n,char keys[]) {//产生密钥流
int i=0,j=0,r;
for(int u=0;u<n;u++)
{
i = (i+1)%256;
j = (j+S[i])%256;
int temp;
temp = S[i];
S[i] = S[j];
S[j] = temp;
r = (S[i]+S[j])%256;
keys[u] =(char) S[r].intValue();
}
System.out.println("密钥流:");
System.out.print(keys);
}
public String encrypt(char keys[],int n,char P[],char C[]) {//加密
for(int i=0;i<n;i++)
{
int op;
op= P[i] ^ keys[i];
C[i] = (char)op;
//System.out.println("op"+op);
//System.out.println("C[i]"+C[i]);
}
String o4 = new String(C);
return o4;
}
public String decrypt(char keys[],int n,char C[]) {//解密
char D[] = new char[256];
for(int i=0;i<n;i++)
{
int op;
op= C[i] ^ keys[i];
D[i] = (char)op;
}
String o4 = new String(D);
return o4;
}
}
Rabbit
Rabbit是一种高速流密码,于 2003 年在 FSE 研讨会上首次提出。Rabbit使用一个 128 位密钥和一个 64 位初始化向量。该加密算法的核心组件是一个位流生成器,该流生成器每次迭代都会加密 128个消息位。最大加密消息长度为264 Bytes,即16TB,若消息超过该长度,则需要更换密钥对剩下的消息进行处理。它是目前安全性较高,加/解密速度比较高效的流密码之一,在各种处理器平台上都有不凡的表现。
class Rabbit
{
private int[] x = new int[8];
private int[] c = new int[8];
private int carry;
public void Rabbit()
{
for(int i = 0; i < 8; i++)
{
x[i] = c[i] = 0;
}
carry = 0;
}
private int g_func(int x)
{
int a = x & 0xffff;
int b = x >>> 16;
int h =( ( ( ( a * a ) >>> 17 ) + ( a * b ) ) >>> 15 ) + b * b;
int l = x * x;
return h ^ l;
}
/**
* @declaration 比较两个有符号整数的十六进制的大小,即作为无符号整数进行比较
* @param x
* @param y
* @return 若(unsigned x) < (unsigned y),则返回1,否则返回0
*/
private int compare(int x, int y)
{
long a = x;
long b = y;
a &= 0x00000000ffffffffl;
b &= 0x00000000ffffffffl;
return (a < b) ? 1 : 0;
}
private int rotL(int x, int y)
{
return ( x << y ) | ( x >>> (32 - y) );
}
private void next_state()
{
int[] g = new int[8];
int[] c_old = new int[8];
int i = 0;
for( i = 0; i < 8; i++)
{
c_old[i] = c[i];
}
c[0] += 0x4d34d34d + carry;
c[1] += 0xd34d34d3 + compare(c[0], c_old[0]);
c[2] += 0x34d34d34 + compare(c[1], c_old[1]);
c[3] += 0x4d34d34d + compare(c[2], c_old[2]);
c[4] += 0xd34d34d3 + compare(c[3], c_old[3]);
c[5] += 0x34d34d34 + compare(c[4], c_old[4]);
c[6] += 0x4d34d34d + compare(c[5], c_old[5]);
c[7] += 0xd34d34d3 + compare(c[6], c_old[6]);
carry = compare(c[7], c_old[7]);
for( i = 0; i < 8; i++)
{
g[i] = g_func(x[i] + c[i]);
}
x[0] = g[0] + rotL(g[7], 16) + rotL(g[6], 16);
x[1] = g[1] + rotL(g[0], 8 ) + g[7];
x[2] = g[2] + rotL(g[1], 16) + rotL(g[0], 16);
x[3] = g[3] + rotL(g[2], 8 ) + g[1];
x[4] = g[4] + rotL(g[3], 16) + rotL(g[2], 16);
x[5] = g[5] + rotL(g[4], 8 ) + g[3];
x[6] = g[6] + rotL(g[5], 16) + rotL(g[4], 16);
x[7] = g[7] + rotL(g[6], 8 ) + g[5];
}
/**
* @declaration 将一个字节数组转化为整数,采用Big-Endian格式进行解析
* @param a 待转化的字节数组
* @param i 字节数组的起始索引
* @return 转化后的整数
*/
public static int os2ip(byte[] a, int i)
{
int x0 = a[i + 3] & 0x000000ff;
int x1 = a[i + 2] << 8 & 0x0000ff00;
int x2 = a[i + 1] << 16 & 0x00ff0000;
int x3 = a[i] << 24 & 0xff000000;
return x0 | x1 | x2 | x3;
}
/**
* @declaration 将整数x转化为4字节数组,采用Big-Endian格式进行解析
* @param x 待转化的整数x
* @return 解析后的字节数组,长度为4
*/
public static byte[] i2osp(int x)
{
byte[] s = new byte[4];
s[3] = (byte)( x & 0x000000ff );
s[2] = (byte)( ( x & 0x0000ff00 ) >>> 8 );
s[1] = (byte)( ( x & 0x00ff0000 ) >>> 16 );
s[0] = (byte)( ( x & 0xff000000 ) >>> 24 );
return s;
}
/**
* @declaration 密钥初始化函数
* @param p_key 长度为128位的密钥数组,若密钥长度小于128位,
* 则必须在填充后再调用该函数
*/
public void keySetup(byte[] p_key)
{
int k0, k1, k2, k3, i;
k0 = os2ip(p_key, 12);
k1 = os2ip(p_key, 8);
k2 = os2ip(p_key, 4);
k3 = os2ip(p_key, 0);
x[0] = k0;
x[2] = k1;
x[4] = k2;
x[6] = k3;
x[1] = ( k3 << 16 ) | ( k2 >>> 16 );
x[3] = ( k0 << 16 ) | ( k3 >>> 16 );
x[5] = ( k1 << 16 ) | ( k0 >>> 16 );
x[7] = ( k2 << 16 ) | ( k1 >>> 16 );
c[0] = rotL(k2, 16);
c[2] = rotL(k3, 16);
c[4] = rotL(k0, 16);
c[6] = rotL(k1, 16);
c[1] = (k0 & 0xffff0000) | (k1 & 0x0000ffff);
c[3] = (k1 & 0xffff0000) | (k2 & 0x0000ffff);
c[5] = (k2 & 0xffff0000) | (k3 & 0x0000ffff);
c[7] = (k3 & 0xffff0000) | (k0 & 0x0000ffff);
carry = 0;
for( i = 0; i < 4; i++)
{
next_state();
}
for( i = 0; i < 8; i++)
{
c[ (i + 4) & 7 ] ^= x[i];
}
}
/**
* @declaration 该函数用于生成128位随机密钥,用于直接和明文进行异或处理
* @param p_dest 产生的128位随机密钥
* @param data_size 需要产生的随机密钥数量,必须是16的倍数
*/
public void getS(byte[] p_dest, long data_size)
{
int i, j, m;
int[] k = new int[4];
byte[] t = new byte[4];
for( i = 0; i < data_size; i+=16)
{
next_state();
k[0] = x[0] ^ ( x[5] >>> 16 ) ^ ( x[3] << 16 );
k[1] = x[2] ^ ( x[7] >>> 16 ) ^ ( x[5] << 16 );
k[2] = x[4] ^ ( x[1] >>> 16 ) ^ ( x[7] << 16 );
k[3] = x[6] ^ ( x[3] >>> 16 ) ^ ( x[1] << 16 );
for( j = 0; j < 4; j++)
{
t = i2osp(k[j]);
for( m = 0; m < 4; m++)
{
p_dest[ j * 4 + m ] = t[m];
}
}
}
}
/**
* @declaration 加密和解密函数
* @param p_src 需要加密或解密的消息,其长度必须是16的倍数,以字节为单位,
* 若不是16的倍数,则需要在调用该函数前进行填充,一般填充值
* 为0的字节
* @param p_dest 加密或解密的结果,其长度必须是16的倍数,以字节为单位
* 并且长度必须大于等于p_src的长度
* @param data_size 需要处理的消息的长度,必须是16的倍数,以字节为单位
* 其值为p_src的长度
*/
public void cipher(byte[] p_src, byte[] p_dest, long data_size)
{
int i, j, m;
int[] k = new int[4];
byte[] t = new byte[4];
for( i = 0; i < data_size; i+=16)
{
next_state();
k[0] = os2ip(p_src, i * 16 + 0) ^ x[0] ^ ( x[5] >>> 16 ) ^ ( x[3] << 16 );
k[1] = os2ip(p_src, i * 16 + 4) ^ x[2] ^ ( x[7] >>> 16 ) ^ ( x[5] << 16 );
k[2] = os2ip(p_src, i * 16 + 8) ^ x[4] ^ ( x[1] >>> 16 ) ^ ( x[7] << 16 );
k[3] = os2ip(p_src, i * 16 + 12) ^ x[6] ^ ( x[3] >>> 16 ) ^ ( x[1] << 16 );
for( j = 0; j < 4; j++)
{
t = i2osp(k[j]);
for( m = 0; m < 4; m++)
{
p_dest[ i * 16 + j * 4 + m ] = t[m];
}
}
}
}
}
public class Main {
public static void main(String[] args) {
/**
* 定义测试密钥key,需要注意的是,由于java没有unsigned类型,
* 所以需要对大于等于0x80的字节进行类型转换,
* 比较方便的办法是都加上(byte)
*/
byte[] key = {
(byte)0xa0, (byte)0x33, (byte)0xd6, (byte)0x78,
(byte)0x6b, (byte)0x05, (byte)0x14, (byte)0xac,
(byte)0xfc, (byte)0x3d, (byte)0x8e, (byte)0x2d,
(byte)0x6a, (byte)0x2c, (byte)0x27, (byte)0x1d
};
/**
* 定义待加密的消息message,密文ciphertext,并初始化为0
*/
byte[] message = new byte[16];
byte[] ciphertext = new byte[16];
for( int i = 0; i < 16; i++)
{
message[i] = (byte)i;
ciphertext[i] = 0;
}
/**
* 调用Rabbit流密码进行加密
*/
Rabbit rtest = new Rabbit();
/*
* 初始化密钥
*/
rtest.keySetup(key);
/*
* 加密
*/
rtest.cipher(message, ciphertext, 16);
for( int i = 0; i < 16; i++)
{
System.out.printf("%02x ", ciphertext[i]);
}
System.out.println();
/**
* 调用Rabbit流密码进行解密
*/
Rabbit rtest2 = new Rabbit();
/*
* 初始化密钥
*/
rtest2.keySetup(key);
byte[] szT = new byte[16];
for( int i = 0; i < 16; i++)
{
szT[i] = 0;
}
/*
* 解密
*/
rtest2.cipher(ciphertext, szT, 16);
for( int i = 0; i < 16; i++)
{
System.out.printf("%02x ", szT[i]);
}
System.out.println();
}
}
Base64
Base64 编码是我们程序开发中经常使用到的编码方法,它用 64个可打印字符来表示二进制数据。这 64 个字符是:小写字母 a-z、大写字母A-Z、数字 0-9、符号”+”、”/“(再加上作为垫字的”=”,实际上是 65个字符),其他所有符号都转换成这个字符集中的字符。Base64编码通常用作存储、传输一些二进制数据编码方法,所以说它本质上是一种将二进制数据转成文本数据的方案。
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class Base64Util {
/***
* BASE64解密
* @param key
* @return
* @throws Exception
*/
public static byte[] decryBASE64(String key) throws Exception{
return (new BASE64Decoder()).decodeBuffer(key);
}
/***
* BASE64加密
* @param key
* @return
* @throws Exception
*/
public static String encryptBASE64(byte[] key) throws Exception{
return (new BASE64Encoder()).encode(key);
}
}
MD5
MD5是将任意长度的数据字符串转化成短小的固定长度的值的单向操作,任意两个字符串不应有相同的散列值。因此MD5 经常用于校验字符串或者文件,因为如果文件的 MD5不一样,说明文件内容也是不一样的。MD5主要用做数据一致性验证、数字签名和安全访问认证,而不是用作加密。
import java.security.MessageDigest;
public class MD5Util {
public static final String KEY_MD5 = "MD5";
/***
* MD5加密(生成唯一的MD5值)
* @param data
* @return
* @throws Exception
*/
public static byte[] encryMD5(byte[] data) throws Exception {
MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
md5.update(data);
return md5.digest();
}
}
SHA
SHA算法是基于MD4算法实现的,作为MD算法的继任者,成为了新一代的消息摘要算法的代表。SHA与MD算法不同之处主要在于摘要长度,SHA算法的摘要更长,安全性更高。
SHA算法家族目前共有SHA-1、SHA-224、SHA-256、SHA-384和SHA-512五种算法,通常将后四种算法并称为SHA-2算法。
import java.security.MessageDigest;
public class SHAUtil {
public static final String KEY_SHA = "SHA";
public static final String ALGORITHM = "SHA-256";
/***
* SHA加密(比MD5更安全)
* @param data
* @return
* @throws Exception
*/
public static byte[] encryptSHA(byte[] data) throws Exception{
MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
sha.update(data);
return sha.digest();
}
public static String SHAEncrypt(final String content) {
try {
MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
byte[] sha_byte = sha.digest(content.getBytes());
StringBuffer hexValue = new StringBuffer();
for (byte b : sha_byte) {
//将其中的每个字节转成十六进制字符串:byte类型的数据最高位是符号位,通过和0xff进行与操作,转换为int类型的正整数。
String toHexString = Integer.toHexString(b & 0xff);
hexValue.append(toHexString.length() == 1 ? "0" + toHexString : toHexString);
}
return hexValue.toString();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
//SHA-256加密
public static String SHA256Encrypt(String sourceStr) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance(ALGORITHM);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
if (null != md) {
md.update(sourceStr.getBytes());
String digestStr = getDigestStr(md.digest());
return digestStr;
}
return null;
}
private static String getDigestStr(byte[] origBytes) {
String tempStr = null;
StringBuilder stb = new StringBuilder();
for (int i = 0; i < origBytes.length; i++) {
tempStr = Integer.toHexString(origBytes[i] & 0xff);
if (tempStr.length() == 1) {
stb.append("0");
}
stb.append(tempStr);
}
return stb.toString();
}
}
HMAC
MAC算法结合了MD和SHA算法的优势,并加入秘钥的支持,是一种更为安全的消息摘要算法。因为MAC算法融合了秘钥散列函数(keyed-Hash),通常我们也把MAC称为HMAC(keyed-Hash Message Authentication Code)。
MAC算法主要集合了MD和SHA两大系列消息摘要算法。MD系列算法有HmacMD2、HmacMD4和HmacMD5三种算法;SHA系列算法有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384和HmacSHA512五种算法。
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class HMACUtil {
public static final String KEY_MAC = "HmacMD5";
/***
* 初始化HMAC密钥
* @return
* @throws Exception
*/
public static String initMacKey() throws Exception{
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC);
SecretKey secreKey = keyGenerator.generateKey();
return Base64Util.encryptBASE64(secreKey.getEncoded());
}
/**
* HMAC加密
* @param data
* @param key
* @return
* @throws Exception
*/
public static byte[] encryHMAC(byte[] data, String key) throws Exception{
SecretKey secreKey = new SecretKeySpec(Base64Util.decryBASE64(key), KEY_MAC);
Mac mac = Mac.getInstance(secreKey.getAlgorithm());
mac.init(secreKey);
return mac.doFinal();
}
}