【算法笔记】AES_算法简单实践

Page content

这篇文章简单的整理了RSA算法的简单实践

1.AES加密算法

我们先看看维基百科的解释。

高级加密标准(Advanced Encryption Standard,缩写:AES),又称Rijndael加密法。
现在,高级加密标准已然成为对称密钥加密中最流行的算法之一。

2.对称加密算法

对称密钥算法(Symmetric-key algorithm)
又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。
这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。
与公开密钥加密相比,要求双方获取相同的密钥是对称密钥加密的主要缺点之一。 常见的对称加密算法有AES、ChaCha20、3DES、Salsa20、DES、Blowfish、IDEA、RC5、RC6、Camellia。 对称加密的速度比公钥加密快很多,在很多场合都需要对称加密。

3.AES简单实践

java实现

package org.example;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;


import org.junit.Test;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.util.Base64;

/**
 * @author : 李明燮
 * @since : 2022/11/6
 * create at : 2022/11/6 10:14 AM
 */
public class AESUtils {
    // 加密
    public static String Encrypt(String sSrc, String sKey) throws Exception {
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }
        // 判断Key是否为16位
        if (sKey.length() != 16) {
            System.out.print("Key长度不是16位");
            return null;
        }
        byte[] raw = sKey.getBytes("utf-8");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
        return new BASE64Encoder().encode(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
    }

    // 解密
    public static String Decrypt(String sSrc, String sKey) throws Exception {
        try {
            // 判断Key是否正确
            if (sKey == null) {
                System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                System.out.print("Key长度不是16位");
                return null;
            }
            byte[] raw = sKey.getBytes("utf-8");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用base64解密
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original, "utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }

    @Test
    public void aesTest() {
        String key = "123456789abcdefg";
        String text = "aes加密测试";
        try {
            String sText = Encrypt(text, key);
            System.out.println("加密后:" + sText);
            String dText = Decrypt(sText, key);
            System.out.println("解密后:" + dText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param data 明文
     * @param key  密钥,长度16
     * @param iv   偏移量,长度16
     * @return 密文
     * @author miracle.qu
     * @Description AES算法加密明文
     */
    public static String encryptAEScbc(String data, String key, String iv) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            int blockSize = cipher.getBlockSize();
            byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;

            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }

            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());  // CBC模式,需要一个向量iv,可增加加密算法的强度

            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);

            return encode(encrypted).trim(); // BASE64做转码。

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param data 密文
     * @param key  密钥,长度16
     * @param iv   偏移量,长度16
     * @return 明文
     * @author miracle.qu
     * @Description AES算法解密密文
     */
    public static String decryptAEScbc(String data, String key, String iv) throws Exception {
        try {
            byte[] encrypted1 = decode(data);//先用base64解密

            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original);
            return originalString.trim();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 编码
     *
     * @param byteArray
     * @return
     */
    public static String encode(byte[] byteArray) {
        return new String(Base64.getEncoder().encode(byteArray));
    }

    /**
     * 解码
     *
     * @param base64EncodedString
     * @return
     */
    public static byte[] decode(String base64EncodedString) {
        return Base64.getDecoder().decode(base64EncodedString);
    }


    @Test
    public void aesCbcTest() {
        String key = "123456789abcdefg";
        String iv = "0123456789abcdef";
        String text = "aes加密测试";

        try {
            String sText = encryptAEScbc(text, key, iv);
            System.out.println("加密后:" + sText);
            String dText = decryptAEScbc(sText, key, iv);
            System.out.println("解密后:" + dText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

NodeJs

var CryptoJS = require("crypto-js");
var key = "123456789abcdefg";
var iv = "0123456789abcdef";

function encrypt(text){
    return CryptoJS.AES.encrypt(text,CryptoJS.enc.Utf8.parse(key),{
        iv:CryptoJS.enc.Utf8.parse(iv),
        mode:CryptoJS.mode.CBC,
        padding:CryptoJS.pad.Pkcs7
    })
}

function decrypt(text){
    var result = CryptoJS.AES.decrypt(text,CryptoJS.enc.Utf8.parse(key),{
        iv:CryptoJS.enc.Utf8.parse(iv),
        mode:CryptoJS.mode.CBC,
        padding:CryptoJS.pad.Pkcs7
    })
    return result.toString(CryptoJS.enc.Utf8)
}

var text=`aes加密测试`;
var encoded=encrypt(text)
console.log(encoded.toString());
console.log('-------------------------------------');
console.log(decrypt(encoded));

Golang

package goaes

import (
 "crypto/aes"
 "crypto/cipher"
 "encoding/base64"
 "errors"
 "fmt"
)

/*
 AES-CBC 加密
 text String 待加密的明文
 key String 秘钥
 iv String iv值
 return Base64, err
*/
func EncryptAESCBC(text, key, iv string) (result string, err error) {
 if len(key) != 16 && len(key) != 24 && len(key) != 32 {
  return "", errors.New("key length must be 16、24、32")
 }

 if len(key) != len(iv) {
  return "", errors.New("IV length must equal block size")
 }

 encrypted, err := CBCEncrypter([]byte(text), []byte(key), []byte(iv))
 if err != nil {
  return "", err
 }

 return base64.StdEncoding.EncodeToString(encrypted), nil
}

/*
 AES-CBC 解密
 encrypter base64 待解密的密文
 key string 秘钥
 iv string iv值
 return String, err
*/
func DecryptAESCBC(encrypter, key, iv string) (result string, err error) {
 if len(key) != 16 && len(key) != 24 && len(key) != 32 {
  return "", errors.New("请确保的key的长度是 16、24、32 中一个。")
 }

 if len(key) != len(iv) {
  return "", errors.New("IV length must equal block size")
 }

 encryptByte, err := base64.StdEncoding.DecodeString(encrypter)
 if err != nil {
  return "", err
 }

 decrypted, err := CBCDecrypter(encryptByte, []byte(key), []byte(iv))
 if err != nil {
  return "", err
 }

 return string(decrypted), nil
}

/*
 CBC 加密
 text 待加密的明文
 key 秘钥
*/
func CBCEncrypter(text []byte, key []byte, iv []byte) ([]byte, error) {
 block, err := aes.NewCipher(key)
 if err != nil {
  return nil, err
 }
 // 填充
 paddText := PKCS7Padding(text, block.BlockSize())

 blockMode := cipher.NewCBCEncrypter(block, iv)

 // 加密
 result := make([]byte, len(paddText))
 blockMode.CryptBlocks(result, paddText)
 // 返回密文
 return result, nil
}

/*
 CBC 解密
 encrypter 待解密的密文
 key 秘钥
*/
func CBCDecrypter(encrypter []byte, key []byte, iv []byte) ([]byte, error) {
 block, err := aes.NewCipher(key)
 if err != nil {
  fmt.Println(err)
 }
 blockMode := cipher.NewCBCDecrypter(block, iv)
 result := make([]byte, len(encrypter))
 blockMode.CryptBlocks(result, encrypter)
 // 去除填充
 result = UnPKCS7Padding(result)
 return result, err
}

/*
 PKCS7Padding 填充模式
 text:明文内容
 blockSize:分组块大小
*/
func PKCS7Padding(text []byte, blockSize int) []byte {
 // 计算待填充的长度
 padding := blockSize - len(text)%blockSize
 var paddingText []byte
 if padding == 0 {
  // 已对齐,填充一整块数据,每个数据为 blockSize
  paddingText = bytes.Repeat([]byte{byte(blockSize)}, blockSize)
 } else {
  // 未对齐 填充 padding 个数据,每个数据为 padding
  paddingText = bytes.Repeat([]byte{byte(padding)}, padding)
 }
 return append(text, paddingText...)
}

/*
 去除 PKCS7Padding 填充的数据
 text 待去除填充数据的原文
*/
func UnPKCS7Padding(text []byte) []byte {
 // 取出填充的数据 以此来获得填充数据长度
 unPadding := int(text[len(text)-1])
 return text[:(len(text) - unPadding)]
}

func MainGoAesCBC() {
 key := "123456789abcdefg"
 iv := "0123456789abcdef"
 text := "aes_CBC加密测试"

 // 加密 []byte
 encrypted, _ := CBCEncrypter([]byte(text), []byte(key), []byte(iv))
 fmt.Println(base64.StdEncoding.EncodeToString(encrypted))

 // 解密 []byte
 decrypted, _ := CBCDecrypter([]byte(encrypted), []byte(key), []byte(iv))
 fmt.Println(string(decrypted))

 // 加密 string
 encryptedStr, _ := EncryptAESCBC(text, key, iv)
 fmt.Println(encryptedStr)
 // 解密 string
 decryptStr, _ := DecryptAESCBC(encryptedStr, key, iv)
 fmt.Println(decryptStr)
}

欢迎大家的意见和交流

email: li_mingxie@163.com