Java下编码、加密的使用与理解

编码算法

URL 编码

目的:
   在使用 URL 向服务器发送数据时,由于很多服务器只能识别 ASCII 字符,但如果URL中包含中文、日文这些非 ASCII 字符时,就需要对其编码后,再发送给服务器。

注意:
   在和其他语言进行数据交互时,如果使用到了 URL 编码算法,需要特别注意两种语言的差异,下面便是实际遇到的一种:

前端传递了一个 URL 编码的用户名s,后端使用不同的实现完成 URL 解码,得到不同的结果s1,s2(正确):
在这里插入图片描述
(urlCodec:org.apache.commons.codec.net.URLCodec)

对正确的用户名去编码、解码,得到:
在这里插入图片描述
结论:Java 直接使用 URLCodec,就可以避免不同语言的解码失败问题。

Base64 编码

完成的功能:
  Base64 编码是对二进制数据进行编码,表示成文本格式,即服务器通用的(字母、数字、+、/、=) 字符,也由于该特性,Base64 编码后,数据长度增加 1/3 。

  在项目中,将报文进行压缩、加密后,最后一步必然是使用 Base64 编码,因为 Base64 编码的字符串,更适合不同平台、不同语言的传输。

Java用例:

		String src="abc^???-)";
        String encode = Base64.getEncoder().encodeToString(src.getBytes("utf-8"));
        System.out.println(encode);     //YWJjXj8/Py0p

        byte[] decode = Base64.getDecoder().decode(encode);
        String decodeSrc = new String(decode);
        System.out.println(decodeSrc);  //abc^???-)

对称加密算法

  对称加密,是为了解决数据传输过程中,被第三方窃取的问题。发送方通过约定的密钥加密,接收方接受到密文后,使用密钥解密便得到明文。

  在整个过程中,密钥的安全性,显的比较重要。密钥的确定有两种方式,一是发送、接受方提前约定好,配置在代码中,二是通过传输临时约定密钥,该种方式需要考虑中间人攻击的情况。

常用的对称加密算法:

算法密钥长度工作模式填充模式
DES56/64ECB/CBC/PCBC/CTR/…NoPadding/PKCS5Padding/…
AES128/192/256ECB/CBC/PCBC/CTR/…NoPadding/PKCS5Padding/PKCS7Padding/…
IDEA128ECBPKCS5Padding/PKCS7Padding/…

DES短时间内可被破解,故不再推荐使用

提前约定密钥的 AES 对称加密

  从上述的表格中可以看到,aes 的密钥可以为三种固定的长度,16、24、32个字符的字符串,其余长度的密钥均会被各种语言平台处理为对应的长度。

   AES/ECB/PKCS5Padding 加密用例:

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class AES {

    public static void main(String[] args) {
        String key="1234567890123456";
        try {
            String encrypt = encrypt("abccccccccabc", key);
            System.out.println(encrypt);//16:EiiaUaAym+SZW2mhCchsHw==   24:D2Hdlvx19upLOQHjr9j8WQ==  32

            String decrypt = decrypt(encrypt, key);
            System.out.println(decrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 加密
    public static String encrypt(String sSrc, String sKey) throws Exception {
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }

        SecretKeySpec skeySpec = new SecretKeySpec(sKey.getBytes("utf-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));

        return Base64.encodeBase64String(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
    }

    //解密
    public static String decrypt(String sSrc, String sKey) throws Exception {
        // 判断Key是否正确
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }
        SecretKeySpec skeySpec = new SecretKeySpec(sKey.getBytes("utf-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);

        byte[] encrypted1 = Base64.decodeBase64(sSrc);//先用base64解密
        byte[] original = cipher.doFinal(encrypted1);//再用aes解密
        String originalString = new String(original, "utf-8");
        return originalString;
    }
}

非对称加密算法RSA

概念

所谓非对称加密,就是加密和解密使用的不是相同的密钥。

公私钥是成对使用的。公钥可以公开给他人使用,私钥非公开保存。可以用私钥去解密他人用公钥加密后的文件内容。

缺点

相比于对称加密而言,非对称加密算法时间复杂度高,一般需要两者配合来使用,实现高效且相对安全的数据传输。

需要注意的是:

在 RSA 加密时,对同一个明文加密,每次都会得到不同的密文。由此可得,解密时,不同的密文,可能得到相同的明文。

RSA 实战工具:

/**
 * 功能:生成公私钥对;按字符串形式存储公私钥对;用存储的公私钥对进行加解密字符串
 */
public class RSA {
    public static void main(String[] args) throws Exception {
        // 创建公钥/私钥对:
        Person alice = new Person();
        alice.generatorPkAndSk();

        //得到字符串类型的公私钥,用于保存
        String publicKeyForSave = alice.getPublicKeyForSave();
        String privateKeyForSave = alice.getPrivateKeyForSave();

        // 明文:
        String plain = "Hello, encrypt use RSA中文 ";

        String encrypt = alice.encrypt(plain, publicKeyForSave);
        //注意:同一个明文加密,每次都会得到不同的密文
        System.out.println(encrypt);

        String decrypt = alice.decrypt(encrypt, privateKeyForSave);
        System.out.println(decrypt);
    }
}

class Person {
    // 私钥:
    PrivateKey sk;
    // 公钥:
    PublicKey pk;

    public void generatorPkAndSk() throws GeneralSecurityException {
        // 生成公钥/私钥对:
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
        kpGen.initialize(1024);
        KeyPair kp = kpGen.generateKeyPair();
        this.sk = kp.getPrivate();
        this.pk = kp.getPublic();
    }

    // 私钥导出存储用
    public String getPrivateKeyForSave() {
        byte[] encoded = this.sk.getEncoded();
        return Base64.getEncoder().encodeToString(encoded);
    }
    // 把公钥导出存储
    public String getPublicKeyForSave() {
        byte[] encoded = this.pk.getEncoded();
        return Base64.getEncoder().encodeToString(encoded);
    }

    /**
     * 用公钥加密
     * @param source 待加密的明文
     * @param publicKey rsa公钥
     * @return
     */
    public String encrypt(String source,String publicKey) throws Exception {
        //生成公钥
        byte[] keyByte = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyByte);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey realPublicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        //使用公钥加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, realPublicKey);
        byte[] bytes = cipher.doFinal(source.getBytes("utf-8"));

        //对返回的密文编码,方便传输存储
        String encryptSource = Base64.getEncoder().encodeToString(bytes);
        return encryptSource;
    }
    /**
     * 用私钥解密
     * @param source 待解密的密文
     * @param privateKey rsa私钥
     * @return
     */
    public String decrypt(String source,String privateKey) throws Exception {
        //生成私钥
        byte[] keyByte = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyByte);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey realPrivateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        //使用私钥解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, realPrivateKey);
        byte[] decodeSource = Base64.getDecoder().decode(source);
        byte[] decryptBytes = cipher.doFinal(decodeSource);

        return new String(decryptBytes);
    }
}

签名算法

   数字签名的目的是为了确认某个信息确实是由某个发送方发送的,其他人都不可能伪造消息,并且,发送方也不能抵赖。

  签名算法使用非对称加密中公私钥对,私钥加密得到的密文实际上就是数字签名,要验证这个签名是否正确,只能用私钥持有者的公钥进行解密验证。私钥就相当于用户身份,而公钥用来给外部验证用户身份。

常用数字签名算法有:

  • MD5withRSA
  • SHA1withRSA
  • SHA256withRSA

在线加解密工具
加密编码使用样例
  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值