package crypto

import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/pem" "errors" "github.com/containous/traefik/v2/pkg/log" )

// pkcsClient 是用于 RSA 加密解密的客户端 type pkcsClient struct { privateKey *rsa.PrivateKey publicKey *rsa.PublicKey }

// Type 表示私钥类型 type Type int64

const ( // 0 PKCS1 Type = iota PKCS8 )

// Encrypt 使用公钥加密明文 func (this *pkcsClient) Encrypt(plaintext []byte) ([]byte, error) { return rsa.EncryptPKCS1v15(rand.Reader, this.publicKey, plaintext) }

// Decrypt 使用私钥解密密文 func (this *pkcsClient) Decrypt(ciphertext []byte) ([]byte, error) { return rsa.DecryptPKCS1v15(rand.Reader, this.privateKey, ciphertext) }

// Sign 使用私钥对数据进行签名 func (this *pkcsClient) Sign(src []byte, hash crypto.Hash) ([]byte, error) { h := hash.New() h.Write(src) hashed := h.Sum(nil) return rsa.SignPKCS1v15(rand.Reader, this.privateKey, hash, hashed) }

// Verify 使用公钥验证签名 func (this *pkcsClient) Verify(src []byte, sign []byte, hash crypto.Hash) error { h := hash.New() h.Write(src) hashed := h.Sum(nil) return rsa.VerifyPKCS1v15(this.publicKey, hash, hashed, sign) }

// Cipher 接口定义了加密解密和签名验证方法 type Cipher interface { Encrypt(plaintext []byte) ([]byte, error) Decrypt(ciphertext []byte) ([]byte, error) Sign(src []byte, hash crypto.Hash) ([]byte, error) Verify(src []byte, sign []byte, hash crypto.Hash) error }

// NewDefault 创建一个默认的 RSA 客户端,使用 PKCS8 格式的私钥 // privateKey 和 publicKey 分别为私钥和公钥的 PEM 编码字符串 func NewDefault(privateKey, publicKey string) (Cipher, error) { blockPri, _ := pem.Decode([]byte(privateKey)) if blockPri == nil { return nil, errors.New("private key error") }

blockPub, _ := pem.Decode([]byte(publicKey))
if blockPub == nil {
	return nil, errors.New("public key error")
}

return NewRsa(blockPri.Bytes, blockPub.Bytes, PKCS8)

}

// NewRsa 创建一个 RSA 客户端,使用指定类型的私钥 // privateKey 和 publicKey 分别为私钥和公钥的字节数组 // privateKeyType 为私钥类型 func NewRsa(privateKey, publicKey []byte, privateKeyType Type) (Cipher, error) { priKey, err := genPriKey(privateKey, privateKeyType) if err != nil { return nil, err } pubKey, err := genPubKey(publicKey) if err != nil { return nil, err } return &pkcsClient{privateKey: priKey, publicKey: pubKey}, nil }

// genPubKey 从字节数组中解析公钥 func genPubKey(publicKey []byte) (*rsa.PublicKey, error) { pub, err := x509.ParsePKIXPublicKey(publicKey) if err != nil { return nil, err } return pub.(*rsa.PublicKey), nil }

// genPriKey 从字节数组中解析私钥,根据 privateKeyType 类型选择解析方式 func genPriKey(privateKey []byte, privateKeyType Type) (*rsa.PrivateKey, error) { var priKey *rsa.PrivateKey var err error switch privateKeyType { case PKCS1: { priKey, err = x509.ParsePKCS1PrivateKey([]byte(privateKey)) if err != nil { return nil, err } } case PKCS8: { prkI, err := x509.ParsePKCS8PrivateKey([]byte(privateKey)) if err != nil { return nil, err } priKey = prkI.(*rsa.PrivateKey) } default: { return nil, errors.New("unsupport private key type") } } return priKey, nil }

// KeyPair 生成一对 RSA 密钥,并以 base64 编码输出 func KeyPair() (priKey, pubKey string, err error) { privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { log.WithoutContext().Errorln(err) return } priKey = base64.StdEncoding.EncodeToString(x509.MarshalPKCS1PrivateKey(privateKey))

// 生成公钥文件
publicKey := &privateKey.PublicKey
derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
	log.WithoutContext().Errorln(err)
	return
}
pubKey = base64.StdEncoding.EncodeToString(derPkix)
return

}

// KeyPairPem 生成一对 RSA 密钥,并以 PEM 格式输出 func KeyPairPem() (priKey, pubKey string, err error) { privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return "", "", err } var pemPrivateBlock = &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey), } priKey = string(pem.EncodeToMemory(pemPrivateBlock))

// 生成公钥文件
publicKey := &privateKey.PublicKey
derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
	return "", "", err
}
block := &pem.Block{
	Type:  "RSA PRIVATE KEY",
	Bytes: derPkix,
}
pubKey = string(pem.EncodeToMemory(block))
return priKey, pubKey, nil

}

// Java 代码示例 package crypto;

import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64;

public class PKCSClient { private PrivateKey privateKey; private PublicKey publicKey;

public PKCSClient(PrivateKey privateKey, PublicKey publicKey) {
	this.privateKey = privateKey;
	this.publicKey = publicKey;
}

public byte[] encrypt(byte[] plaintext) throws Exception {
	// Not implemented
	return null;
}

public byte[] decrypt(byte[] ciphertext) throws Exception {
	// Not implemented
	return null;
}

public byte[] sign(byte[] src, String algorithm) throws Exception {
	Signature signature = Signature.getInstance(algorithm);
	signature.initSign(privateKey);
	signature.update(src);
	return signature.sign();
}

public boolean verify(byte[] src, byte[] sign, String algorithm) throws Exception {
	Signature signature = Signature.getInstance(algorithm);
	signature.initVerify(publicKey);
	signature.update(src);
	return signature.verify(sign);
}

public static PKCSClient loadPrivateKey(String privateKeyPath, String algorithm) throws Exception {
	byte[] privateKeyBytes = Files.readAllBytes(Paths.get(privateKeyPath));
	PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
	KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
	PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
	return new PKCSClient(privateKey, null);
}

public static PKCSClient loadPublicKey(String publicKeyPath, String algorithm) throws Exception {
	byte[] publicKeyBytes = Files.readAllBytes(Paths.get(publicKeyPath));
	X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
	KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
	PublicKey publicKey = keyFactory.generatePublic(keySpec);
	return new PKCSClient(null, publicKey);
}

public static void main(String[] args) throws Exception {
	// Load private key from file
	Path privateKeyPath = Paths.get("private_key.pem");
	byte[] privateKeyBytes = Files.readAllBytes(privateKeyPath);
	String privateKeyString = new String(privateKeyBytes, StandardCharsets.UTF_8);
	privateKeyString = privateKeyString.replaceAll("\n", "")
			.replace("-----BEGIN PRIVATE KEY-----", "")
			.replace("-----END PRIVATE KEY-----", "");
	byte[] privateKeyData = Base64.getDecoder().decode(privateKeyString);
	PKCSClient pkcsClient = PKCSClient.loadPrivateKey(privateKeyData, "RSA");

	// Load public key from file
	Path publicKeyPath = Paths.get("public_key.pem");
	byte[] publicKeyBytes = Files.readAllBytes(publicKeyPath);
	String publicKeyString = new String(publicKeyBytes, StandardCharsets.UTF_8);
	publicKeyString = publicKeyString.replaceAll("\n", "")
			.replace("-----BEGIN PUBLIC KEY-----", "")
			.replace("-----END PUBLIC KEY-----", "");
	byte[] publicKeyData = Base64.getDecoder().decode(publicKeyString);
	pkcsClient.setPublicKey(publicKeyData);

	// Encrypt and Decrypt
	byte[] plaintext = "Hello, World!".getBytes(StandardCharsets.UTF_8);
	byte[] ciphertext = pkcsClient.encrypt(plaintext);
	byte[] decryptedText = pkcsClient.decrypt(ciphertext);

	// Sign and Verify
	byte[] src = "Hello, World!".getBytes(StandardCharsets.UTF_8);
	String algorithm = "SHA256withRSA";
	byte[] sign = pkcsClient.sign(src, algorithm);
	boolean verified = pkcsClient.verify(src, sign, algorithm);
}

}


原文地址: https://www.cveoy.top/t/topic/phiw 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录