本文主要介绍 java AES 中出现的随机算法 SHA1PRNG 生成key,在 golang 中的实现方法
描述
JAVA 代码示例:
// java 代码
// content:test123
// encryptKey:123456
// 加密结果为:668C826342B8703D86E8BBF404610499
public static byte[] encrypt(String content, String encryptKey) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(encryptKey.getBytes());
kgen.init(128, secureRandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES"); // AES 和 AES/ECB/PKCS5Padding 等价
byte[] byteContent = content.getBytes("utf-8");
cipher.init(1, key);
byte[] result = cipher.doFinal(byteContent);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
golang 实现
golang 示例:
// content:test123
// encryptKey:123456
// 加密结果为:668C826342B8703D86E8BBF404610499
// 和 java 结果相对应了,解密也一样对 key 加一步处理就行
func AesEncryptECB(origData []byte, key []byte) (encrypted []byte) {
key, _ = AesSha1prng(key, 128) // 比示例一多出这一步
cipher, _ := aes.NewCipher(generateKey(key))
length := (len(origData) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, origData)
pad := byte(len(plain) - len(origData))
for i := len(origData); i < len(plain); i++ {
plain[i] = pad
}
encrypted = make([]byte, len(plain))
// 分组分块加密
for bs, be := 0, cipher.BlockSize(); bs <= len(origData); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted
}
// 模拟 java SHA1PRNG 处理
func AesSha1prng(keyBytes []byte, encryptLength int) ([]byte, error) {
hashs := Sha1(Sha1(keyBytes))
maxLen := len(hashs)
realLen := encryptLength / 8
if realLen > maxLen {
return nil, errors.New("invalid length!")
}
return hashs[0:realLen], nil
}
func Sha1(data []byte) []byte {
h := sha1.New()
h.Write(data)
return h.Sum(nil)
}
func generateKey(key []byte) (genKey []byte) {
genKey = make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return genKey
}
go版SHA1PRNG 完整代码:
package test
import (
"crypto/aes"
"crypto/sha1"
"encoding/hex"
"errors"
"testing"
)
func Test_Crypto(t *testing.T) {
str := []byte("test123")
key := []byte("123456")
// 加密
res, err := AesEncryptECB(str, key)
if err != nil {
t.Fatal(err)
}
t.Log(hex.EncodeToString(res)) // 输出:668c826342b8703d86e8bbf404610499
// 解密
de, err := AesDecryptECB(res, key)
if err != nil {
t.Fatal(err)
}
t.Log(string(de))
}
// content:test123
// encryptKey:123456
// 加密结果为:668C826342B8703D86E8BBF404610499
// 此时就和 java 结果相对应了,解密也一样对 key 加一步处理就行
func AesEncryptECB(src []byte, key []byte) ([]byte, error) {
key, err := AesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return nil, err
}
cipher, _ := aes.NewCipher(generateKey(key))
length := (len(src) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, src)
pad := byte(len(plain) - len(src))
for i := len(src); i < len(plain); i++ {
plain[i] = pad
}
encrypted := make([]byte, len(plain))
// 分组分块加密
for bs, be := 0, cipher.BlockSize(); bs <= len(src); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return encrypted, nil
}
func AesDecryptECB(encrypted []byte, key []byte) ([]byte, error) {
key, err := AesSha1prng(key, 128) // 比示例一多出这一步
if err != nil {
return nil, err
}
cipher, _ := aes.NewCipher(generateKey(key))
decrypted := make([]byte, len(encrypted))
//
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
}
trim := 0
if len(decrypted) > 0 {
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
}
return decrypted[:trim], nil
}
// 模拟 java SHA1PRNG 处理
func AesSha1prng(keyBytes []byte, encryptLength int) ([]byte, error) {
hashs := Sha1(Sha1(keyBytes))
maxLen := len(hashs)
realLen := encryptLength / 8
if realLen > maxLen {
return nil, errors.New("invalid length!")
}
return hashs[0:realLen], nil
}
func Sha1(data []byte) []byte {
h := sha1.New()
h.Write(data)
return h.Sum(nil)
}
func generateKey(key []byte) (genKey []byte) {
genKey = make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return genKey
}