【go笔记】golang 实现Java AES加密使用SHA1PRNG生成KEY的算法

Viewed 8

本文主要介绍 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
}
0 Materials