注:OpenSSL 加密后的密文格式为「Salted__ + 8位salt + 密文」,并不是「8位salt + 16位iv + 4位iter + 密文」。iv 和 key 是根据 salt 算出来的,并未存于密文中;原则上密码需要32位,但由于密码会被 sha256 后使用,所以密码长度可以不是32位。
OpenSSL
echo "your_message_here" | openssl enc -aes-256-cbc -a -md sha256 -pbkdf2 -iter 1000 -salt -pass pass:bUGJyKOieYiy9vScxZuBC2nGshkFEc3B echo "U2FsdGVkX198FFzAbgWbsK+NZn2IAvDjx3zF0nnq3BQ=" | openssl enc -aes-256-cbc -d -a -md sha256 -pbkdf2 -iter 1000 -salt -pass pass:bUGJyKOieYiy9vScxZuBC2nGshkFEc3B # windows 命令行时 echo 后的字符串不要加引号! # -p 参数可显示 iv, key
AutoHotKey v1
crypt(message, password, isEncrypt := true) { tempFile := A_Temp . "\input.txt" FileDelete, %tempFile% FileAppend, %message%, %tempFile% outFile := A_Temp . "\output.txt" FileDelete, %outFile% cmd := "cmd /c openssl enc -aes-256-cbc -a -md sha256 -pbkdf2 -iter 1000 -salt -pass pass:" . password . " -in """ . tempFile . """ -out """ . outFile . """" . (isEncrypt ? " -e" : " -d") RunWait, %cmd%, , Hide FileRead, encrypted, %outFile% FileDelete, %tempFile% FileDelete, %outFile% return encrypted } ; 示例用法 msg := "your_message_here" pwd := "your_password_here" result := crypt(msg, pwd, true) result := result != "" ? result : msg MsgBox, 加密结果:`n%result% decrypted := crypt(result, pwd, false) decrypted := decrypted != "" ? decrypted : result MsgBox, 解密结果:`n%decrypted%
注:文章 同步剪贴板内容 AutoHotKey v1 需要这里的代码。
为什么使用文件而不是 echo “string” ?因为 windows 的 echo 没有 -e 参数,处理不了有换行的多行文本。echo 多行文本时遇到换行就执行命令了,走不到后边的 openssl 。
另,以上代码使用 RunWait 调用 OpenSSL 实现,如果必须用纯 AutoHotkey 实现(不调用 openssl.exe),需要:
- 实现 PBKDF2-HMAC-SHA256(可用 AHK 脚本或 DLL)
- 实现 AES-256-CBC(可用 AHK 脚本或 DLL)
- 实现 PKCS7 填充
- 拼接 Salted__ + salt + 密文
这非常复杂,AutoHotkey 原生不支持这些算法,通常需要调用外部 DLL(如 OpenSSL DLL、Crypt32.dll、bcrypt.dll),或者用 COM 对象(如 CAPICOM),但 CAPICOM 不支持 PBKDF2-HMAC-SHA256。
推荐:用 openssl.exe 命令行,AutoHotkey 只做自动化。
Hammerspoon lua
function crypt(message, password, isEncrypt) -- 1. 写入临时文件 local tmpfile = os.tmpname() local f = io.open(tmpfile, "w") f:write(message) f:close() -- 2. 构造 openssl 命令 local mode = isEncrypt == false and "-d" or "-e" local cmd = string.format( [[openssl enc -aes-256-cbc -a -md sha256 -pbkdf2 -iter 1000 -salt -pass pass:%s -in "%s" %s]], password, tmpfile, mode ) -- 3. 执行命令 local output, status = hs.execute(cmd, true) -- 4. 删除临时文件 os.remove(tmpfile) -- 5. 返回结果 return status and output or nil end -- 示例用法 local message = [[ line1 line2 line3 ]] local password = "your_password_here" -- 加密 local encrypted = crypt(message, password) if encrypted then hs.alert.show("加密结果:\n" .. encrypted) print("加密结果:\n" .. encrypted) else hs.alert.show("加密失败") print("加密失败") end -- 解密 local decrypted = crypt(encrypted, password, false) if decrypted then hs.alert.show("解密结果:\n" .. decrypted) else hs.alert.show("解密失败") end
注:使用 openssl.exe 命令,Hammerspoon 只做自动化,理由同上边 AutoHotKey。另,同步剪贴板内容 Hammerspoon需要这里的代码。
PHP
// 加密函数 function encrypt($data, $password, $iterations = 1000) { $salt = random_bytes(8); // 生成指定长度的随机盐值 $derived = deriveKeyAndIV($password, $salt, $iterations); // 派生密钥和 IV $key = $derived['key']; $iv = $derived['iv']; $encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); // 加密数据 return base64_encode("Salted__" . $salt . $encrypted); // 构造 OpenSSL 格式的密文并 Base64 编码 } // 解密函数 function decrypt($encryptedData, $password, $iterations = 1000) { $data = base64_decode($encryptedData); // 解码 Base64 数据 if (substr($data, 0, 8) !== "Salted__") { throw new Exception("Invalid encrypted data format."); } $salt = substr($data, 8, 8); // 提取盐值(8 字节) $encrypted = substr($data, 16); // 提取加密数据 $derived = deriveKeyAndIV($password, $salt, $iterations); // 派生密钥和 IV $key = $derived['key']; $iv = $derived['iv']; return openssl_decrypt($encrypted, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); // 解密数据 } // 使用 PBKDF2 派生密钥和 IV function deriveKeyAndIV($password, $salt, $iterations = 1000, $keySize = 32, $ivSize = 16) { $derived = hash_pbkdf2('sha256', $password, $salt, $iterations, $keySize + $ivSize, true); $key = substr($derived, 0, $keySize); $iv = substr($derived, $keySize, $ivSize); return ['key' => $key, 'iv' => $iv]; }