@ -7,9 +7,13 @@
package crypto
package crypto
import (
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/base64"
"fmt"
"fmt"
"io"
"golang.org/x/crypto/bcrypt"
"golang.org/x/crypto/bcrypt"
)
)
@ -58,3 +62,75 @@ func GenerateClientID() string {
func GenerateClientSecret ( ) string {
func GenerateClientSecret ( ) string {
return GenerateSecret ( 64 )
return GenerateSecret ( 64 )
}
}
// deriveKey 从密钥字符串派生32字节AES密钥
func deriveKey ( key string ) [ ] byte {
hash := sha256 . Sum256 ( [ ] byte ( key ) )
return hash [ : ]
}
// Encrypt 使用AES-GCM加密数据
// key: 加密密钥( 会被派生为32字节)
// plaintext: 明文数据
// 返回: base64编码的密文( 包含nonce)
func Encrypt ( key , plaintext string ) ( string , error ) {
if key == "" || plaintext == "" {
return "" , fmt . Errorf ( "key and plaintext cannot be empty" )
}
block , err := aes . NewCipher ( deriveKey ( key ) )
if err != nil {
return "" , err
}
gcm , err := cipher . NewGCM ( block )
if err != nil {
return "" , err
}
nonce := make ( [ ] byte , gcm . NonceSize ( ) )
if _ , err := io . ReadFull ( rand . Reader , nonce ) ; err != nil {
return "" , err
}
ciphertext := gcm . Seal ( nonce , nonce , [ ] byte ( plaintext ) , nil )
return base64 . StdEncoding . EncodeToString ( ciphertext ) , nil
}
// Decrypt 使用AES-GCM解密数据
// key: 解密密钥
// ciphertext: base64编码的密文( 包含nonce)
// 返回: 明文数据
func Decrypt ( key , ciphertext string ) ( string , error ) {
if key == "" || ciphertext == "" {
return "" , fmt . Errorf ( "key and ciphertext cannot be empty" )
}
data , err := base64 . StdEncoding . DecodeString ( ciphertext )
if err != nil {
return "" , fmt . Errorf ( "failed to decode ciphertext: %w" , err )
}
block , err := aes . NewCipher ( deriveKey ( key ) )
if err != nil {
return "" , err
}
gcm , err := cipher . NewGCM ( block )
if err != nil {
return "" , err
}
nonceSize := gcm . NonceSize ( )
if len ( data ) < nonceSize {
return "" , fmt . Errorf ( "ciphertext too short" )
}
nonce , encrypted := data [ : nonceSize ] , data [ nonceSize : ]
plaintext , err := gcm . Open ( nil , nonce , encrypted , nil )
if err != nil {
return "" , fmt . Errorf ( "failed to decrypt: %w" , err )
}
return string ( plaintext ) , nil
}