浅谈加解密算法

本文探讨了如何在整合多个 lbs 服务过程中,通过采用对称加密(如DES与AES)确保数据安全,以及非对称加密(如RSA)的公私钥机制。重点介绍了DES、3DES、AES算法的应用和安全特性,以及RSA在实际场景中的使用。散列算法如MD5也被提及用于验证消息完整性。
摘要由CSDN通过智能技术生成

浅谈加解密算法

背景

早之前,公司有很多套lbs服务,散落在各个部门。大数据部门也拥有自己的一套lbs。这套lbs应用范围较广,功能较齐全。
所以,现阶段,出于成本节约、易用性、统一管理的考虑,我们把其他部门的lbs也整合过来了。
整合过来后,面临一个问题:无法规范地管理业务方,并保证系统的安全性。
因此,我们需要一套加密算法来解决这个问题。

加密和解密

加密

数据加密的基本过程,就是对原来为明文的文件或数据按某种算法进行处理,使其成为 不可读的一段代码,通常称为“密文”。通过这样的途径,来达到保护数据不被非法人窃取、阅读的目的。

解密

加密的逆过程为解密,即将该编码信息转化为其原来数据的过程。

加密算法

加密算法分成对称加密和非对称加密。

  • 对称加密的加密与解密的密钥是相同的
  • 非对称加密的加密与解密的密钥是不同的

还有一类加密算法是不需要密钥的,它叫散列算法。

对称加密

对称加密算法又称为共享密钥加密算法。在对称加密算法中,使用的密钥只有一个,发送和接收双方都使用这个密钥对数据进行加密和解密。这就要求加密和解密方事先都必须知道加密的密钥。

DES

DES加密算法出自IBM的研究,后来被美国政府正式采用,之后开始广泛流传。但近些年使用越来越少,因为DES使用的是56位密钥,以现代的计算能力,24小时内即可被破解。
顺带说一下3DES(Triple DES),它是DES向AES过渡的加密算法,使用3条56位的密钥对数据进行三次加密。是 DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。比起最初的DES,3DES更为安全。
使用Java实现DES加密解密,注意密码长度要是8的倍数。

//偏移量,长度必须为8的倍数
private static String IV = "12345678";
//钥匙,长度必须为8的倍数
private static String KEY = "87654321";

public static void main(String[] args) {
    //字符串编码
    System.out.println("编码结果:" + encrypt("hello world"));
    //字符串解码
    System.out.println("编码结果:" + decrypt("iug3JXsgvoWaRv0QF3cODw=="));
}

//加密
public static String encrypt(String str) {
    try {
        byte[] bytes = str.getBytes();
        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());
        SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), "DES");
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        bytes = cipher.doFinal(bytes);
        bytes = Base64.getEncoder().encode(bytes);
        return new String(bytes);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

//解密
public static String decrypt(String str) {
    try {
        byte[] bytes = Base64.getDecoder().decode(str);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());
        SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), "DES");
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        bytes = cipher.doFinal(bytes);
        return new String(bytes);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}
编码结果:iug3JXsgvoWLcJXvki5H7w==
编码结果:hello word
AES

高级加密标准(Advanced Encryption Standard,缩写:AES),在密码学中被称为Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。简单说就是DES的增强版,比DES的加密强度更高。
AES与DES一样,一共有4种加密模式:电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB);5种填充方式:NoPadding(不填充)、PKCS5Padding(缺几个字节就补充几个字节的几)、PKCS7Padding(缺几个字节就补几个字节的0)、ISO10126Padding(填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节填充随机数据)。

//偏移量,必须16位、24位、32位、64位
private static String IV ="asdfgh1234567890";
//钥匙,必须16位、24位、32位、64位
private static String KEY = "1234567890asdfgh";

public static void main(String[] args) {
    //字符串编码
    System.out.println("编码结果:" + encrypt("hello world"));
    //字符串解码
    System.out.println("编码结果:" + decrypt("UePyU9tACUkzOEHYFMUsNg=="));
}

//加密
public static String encrypt(String str) {
    try {
        byte[] bytes = str.getBytes();
        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());
        SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        bytes = cipher.doFinal(bytes);
        bytes = Base64.getEncoder().encode(bytes);
        return new String(bytes);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

//解密
public static String decrypt(String str) {
    try {
        byte[] bytes = Base64.getDecoder().decode(str);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());
        SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        bytes = cipher.doFinal(bytes);
        return new String(bytes);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }   
}
编码结果:4e0lnjIW6s3vCd2SYMs5Lw==
编码结果:hello word

非对称加密

在通信双方,如果使用非对称加密,一般遵从这样的原则:公钥加密,私钥解密。因为公钥是公开的,若用来解密,那么很容易被不必要的人解密消息。因此,私钥也可以认为是个人身份的证明。

RSA

1977年,三位数学家Rivest、Shamir和Adleman设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。
这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。

public static String RSA_ALGORITHM = "RSA";
public static String UTF8 = "UTF-8";

/**
 * 密钥长度,DSA算法的默认密钥长度是1024
 * 密钥长度必须是64的倍数,在512到65536位之间
 * */
private static final int KEY_SIZE=1024;

public static void main(String[] args) throws Exception {
    String password = "1234abcd5678";
    KeyStore keys = createKeys();
    byte[] publicKey = getPublicKey(keys);
    byte[] privateKey = getPrivateKey(keys);
    System.out.println("公钥:"+ Base64.encode(publicKey));
    System.out.println("私钥:"+ Base64.encode(privateKey));

    byte[] encryptByPublicKey = encryptByPublicKey(password.getBytes(), publicKey);
    System.out.println("使用公钥加密后的数据:"+Base64.encode(encryptByPublicKey));

    byte[] decryptByPrivateKey = decryptByPrivateKey(encryptByPublicKey, privateKey);
    System.out.println("使用私钥解密后的数据:"+new String(decryptByPrivateKey));

}

/**
 * 生成密钥对
 * @return 密钥对对象
 * @throws NoSuchAlgorithmException
 */
public static KeyStore createKeys() throws NoSuchAlgorithmException {
    //KeyPairGenerator用于生成公钥和私钥对。密钥对生成器是使用 getInstance 工厂方法
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
    keyPairGenerator.initialize(KEY_SIZE);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    KeyStore keyStore = new KeyStore( publicKey, privateKey);
    return keyStore;
}

/**
 * 获取私钥
 * @param keyStore
 * @return
 */
private static byte[] getPrivateKey(KeyStore keyStore){
    return ((RSAPrivateKey)keyStore.privateKey).getEncoded();
}

/**
 * 获取公钥
 * @param keyStore
 * @return
 */
private static byte[] getPublicKey(KeyStore keyStore){
    return ((RSAPublicKey)keyStore.publicKey).getEncoded();
}

/**
 * 私钥加密
 * @param data 待加密数据
 * @param key 密钥
 * @return byte[] 加密数据
 * */
public static byte[] encryptByPrivateKey(byte[] data,byte[] key) throws Exception{

    //取得私钥
    PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
    KeyFactory keyFactory=KeyFactory.getInstance(RSA_ALGORITHM);
    //生成私钥
    PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
    //数据加密
    Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.ENCRYPT_MODE, privateKey);
    return cipher.doFinal(data);
}

/**
 * 公钥加密
 * @param data
 * @param key
 * @return
 * @throws NoSuchAlgorithmException
 * @throws InvalidKeySpecException
 * @throws NoSuchPaddingException
 * @throws BadPaddingException
 * @throws IllegalBlockSizeException
 * @throws InvalidKeyException
 */
private static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
    //实例化密钥工厂
    KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
    //初始化公钥,根据给定的编码密钥创建一个新的 X509EncodedKeySpec。
    X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key);
    PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
    //数据加密
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.ENCRYPT_MODE,publicKey);
    return cipher.doFinal(data);
}

/**
 * 私钥解密
 * @param data 待解密数据
 * @param key 密钥
 * @return byte[] 解密数据
 * */
public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws Exception{
    //取得私钥
    PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
    KeyFactory keyFactory=KeyFactory.getInstance(RSA_ALGORITHM);
    //生成私钥
    PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
    //数据解密
    Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    return cipher.doFinal(data);
}

/**
 * 公钥解密
 * @param data 待解密数据
 * @param key 密钥
 * @return byte[] 解密数据
 * */
public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception{

    //实例化密钥工厂
    KeyFactory keyFactory=KeyFactory.getInstance(RSA_ALGORITHM);
    //初始化公钥
    //密钥材料转换
    X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
    //产生公钥
    PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
    //数据解密
    Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
    cipher.init(Cipher.DECRYPT_MODE, pubKey);
    return cipher.doFinal(data);
}


//定义密钥类
@Data
@AllArgsConstructor
public static class KeyStore{
    private Object publicKey;
    private Object privateKey;
}
公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHTwX+IRPCBjoViOiXb2skxjb4BiNR/ig+lRPO
PjF/craPB3OBMyf3Amt940slPTLEsQRKwZgYM6tUOBGLBUvYlN/+wXYXq0WO5qgxu0ZGMCpZmqDH
A6i6+GllPahEJkeb11AQ4/v0vSKJNTgzGkwkzjrt1Kb5/i8CSW3ngBXOkQIDAQAB
私钥:MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIdPBf4hE8IGOhWI6JdvayTGNvgG
I1H+KD6VE84+MX9yto8Hc4EzJ/cCa33jSyU9MsSxBErBmBgzq1Q4EYsFS9iU3/7BdherRY7mqDG7
RkYwKlmaoMcDqLr4aWU9qEQmR5vXUBDj+/S9Iok1ODMaTCTOOu3Upvn+LwJJbeeAFc6RAgMBAAEC
gYBIR7V60K6eSfdDQ7SEGNfSeDQrABRkG3HiJH7FAMIuQ9gzxZY1IV+q+tbzE7UzumJhYfJaANq/
qvJN9fmhGv4tcebFgMIVh4B256A5S6ejwC936dfSjAfYymAj0sdPBZt0Mbf+JlEujGH+TbbRieUd
HlITMHcv2OmDDT7WRrZ9QQJBAO/vg1dlDOpBJw8qSeleDdE5X5XueUrQhg5xp7SsG4Ensq9Rqwfw
BA0FIaRy5/yFE12e6V1KRF/VixBOu2Npz7kCQQCQXjWGmkO2nJiDMYcuGjZPXyFGwFrt6GXNlNxO
aWK4g3/3TI+nrhnf5cCLhPx89VsFfRUN3QK4RtHAotXuaHGZAkEA1jLB02Sf+gU+JHjBUTgpJ66L
meMyn0q3Uu++Izo+t7fD+mXzRPvN8f2xwgje9/2pgzvZ4/HoRpHyOxW+joqo6QJAeaVISND3uYmd
4P38v9YKaTrpWSp/8/NcxKtoLxIRwxPa4dA7Q7kpyEVZxrYZ4lkDh05sTTArOIdD+qO6y5ZqEQJB
AJbIOFnPaIqbsn76ATGCi10fJorZUQGGc3UYm4/pFsqrDawDTVI/3ogkbnFFLn5RWQbls4l3Yhu+
99w65lNhSHM=
使用公钥加密后的数据:LDW0q/vjx8tOCAUIHTyQU+Talf9oiavQvR942ANc+sCFSyJwIRELW5CIbukffdFks08ugxFnkFD2
FeU63tjhqVY6G1R2Qmq7vNsBj4SWceOrIJ4gam95XJO6dCN1YCnNq46GPcenGi4f9zi91r9UeTUs
P+fjidEFNyRxfotZd9A=
使用私钥解密后的数据:1234abcd5678

散列算法

散列算法可以将消息转换成一个固定长度的唯一的字符串。唯一的意思是不同的消息转换成的摘要是不同的,并且能狗保证唯一。
这个过程是不可逆的,即不能通过摘要反推出明文。
利用这一特性,散列算法可以用来验证消息的完整性。

MD5

MD5是将任意长度的数据字符串转化成短小的固定长度的值的单向操作,任意两个字符串不应该有相同的散列值。
MD5主要做数据的一致性验证、数字签名和安全访问认证,而不是用作加密。
MD5算法具有以下特点:

  • 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
  • 容易计算:从原数据计算出MD5值很容易。
  • 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  • 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
/**
 * MD5方法
 *
 * @param text 明文
 * @param salt 盐
 * @return 密文
 * @throws Exception
 */
public static String md5(String text, String salt) throws Exception {
    //加密后的字符串
    String encodeStr = DigestUtils.md5Hex(String.format("%s%s", text , salt));
    return encodeStr;
}

各算法对比

算法类型特点优势缺陷代表算法应用场景
对称加密加密、解密的密钥相或可推算性能好需要提前共享密钥,易泄漏DES、AES、敏感数据加密
非对称加密加密、解密的密钥毫无相关提供公钥给业务方即可性能较差RSA、DSA密钥
散列算法不可逆MD5、SHA1验证消息完整性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值