【已解决】(C#)AES算法 AesEncrypt 如何在AU3实现
本帖最后由 autoit3CN 于 2020-1-11 01:38 编辑public static string AesEncrypt(string input, string password, string salt)
{
byte[] bytes = Encoding.UTF8.GetBytes(input);
byte[] bytes2 = Encoding.UTF8.GetBytes(salt);
using (AesManaged aesManaged = new AesManaged())
{
Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, bytes2);
aesManaged.BlockSize = aesManaged.LegalBlockSizes.MaxSize;
aesManaged.KeySize = aesManaged.LegalKeySizes.MaxSize;
aesManaged.Key = rfc2898DeriveBytes.GetBytes(aesManaged.KeySize / 8);
aesManaged.IV = rfc2898DeriveBytes.GetBytes(aesManaged.BlockSize / 8);
using (ICryptoTransform transform = aesManaged.CreateEncryptor())
{
MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(bytes, 0, bytes.Length);
}
return Convert.ToBase64String(memoryStream.ToArray());
}
}
}
public Rfc2898DeriveBytes(string password, byte[] salt, int iterations)
: this(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(password), salt, iterations)
{
}
public class Rfc2898DeriveBytes : DeriveBytes
{
private const int BlockSize = 20;
private byte[] m_buffer;
private byte[] m_salt;
private HMACSHA1 m_hmacsha1;
private uint m_iterations;
private uint m_block;
private int m_startIndex;
private int m_endIndex;
public int IterationCount
{
get
{
return (int)m_iterations;
}
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
}
m_iterations = (uint)value;
Initialize();
}
}
public byte[] Salt
{
get
{
return (byte[])m_salt.Clone();
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (value.Length < 8)
{
throw new ArgumentException(Environment.GetResourceString("Cryptography_PasswordDerivedBytes_FewBytesSalt"));
}
m_salt = (byte[])value.Clone();
Initialize();
}
}
public Rfc2898DeriveBytes(string password, byte[] salt)
: this(password, salt, 1000)
{
}
public Rfc2898DeriveBytes(string password, byte[] salt, int iterations)
: this(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false).GetBytes(password), salt, iterations)
{
}
public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations)
{
Salt = salt;
IterationCount = iterations;
m_hmacsha1 = new HMACSHA1(password);
Initialize();
}
public override byte[] GetBytes(int cb)
{
if (cb <= 0)
{
throw new ArgumentOutOfRangeException("cb", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
}
byte[] array = new byte;
int i = 0;
int num = m_endIndex - m_startIndex;
if (num > 0)
{
if (cb < num)
{
Buffer.InternalBlockCopy(m_buffer, m_startIndex, array, 0, cb);
m_startIndex += cb;
return array;
}
Buffer.InternalBlockCopy(m_buffer, m_startIndex, array, 0, num);
m_startIndex = (m_endIndex = 0);
i += num;
}
for (; i < cb; i += 20)
{
byte[] src = Func();
int num2 = cb - i;
if (num2 > 20)
{
Buffer.InternalBlockCopy(src, 0, array, i, 20);
continue;
}
Buffer.InternalBlockCopy(src, 0, array, i, num2);
i += num2;
Buffer.InternalBlockCopy(src, num2, m_buffer, m_startIndex, 20 - num2);
m_endIndex += 20 - num2;
return array;
}
return array;
}
public override void Reset()
{
Initialize();
}
private void Initialize()
{
if (m_buffer != null)
{
Array.Clear(m_buffer, 0, m_buffer.Length);
}
m_buffer = new byte;
m_block = 1u;
m_startIndex = (m_endIndex = 0);
}
private byte[] Func()
{
byte[] array = Utils.Int(m_block);
m_hmacsha1.TransformBlock(m_salt, 0, m_salt.Length, m_salt, 0);
m_hmacsha1.TransformFinalBlock(array, 0, array.Length);
byte[] array2 = m_hmacsha1.Hash;
m_hmacsha1.Initialize();
byte[] array3 = array2;
for (int i = 2; i <= m_iterations; i++)
{
array2 = m_hmacsha1.ComputeHash(array2);
for (int j = 0; j < 20; j++)
{
array3 ^= array2;
}
}
m_block++;
return array3;
}
}public static string ToBase64String(byte[] inArray)
{
if (inArray == null)
{
throw new ArgumentNullException("inArray");
}
return ToBase64String(inArray, 0, inArray.Length, Base64FormattingOptions.None);
}
求问: AesEncrypt(string input, string password, string salt)这个C#函数如何转化AU3所用?
三个参数已有:
input=AAAAAA|123456(私人账号|密码)
SecretKey Password = "Z_h$W@123";
SecretKey Salt = "123@Z_h$W";
自己摸索结果:
Cryptography.AesEncrypt结果:IA6PCpe/zZEtICN7E/EFXw==
但是我采用acn论坛、英文论坛、其他在线解密网站(http://tool.chacuo.net/cryptaes),
结算结果均为错误的或其他:WznD9w7icLss4DLVThTFUQ==
其中使用英文论坛:
#include <ComboConstants.au3>
#include <Crypt.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <StringConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Global $g_hKey = -1, $g_idInputEdit = -1, $g_idOutputEdit = -1
Example()
Func Example()
Local $hGUI = GUICreate("Realtime Encryption", 400, 320)
$g_idInputEdit = GUICtrlCreateEdit("AAAAAA|123456", 0, 0, 400, 150, $ES_WANTRETURN)
$g_idOutputEdit = GUICtrlCreateEdit("", 0, 150, 400, 150, $ES_READONLY)
Local $idCombo = GUICtrlCreateCombo("", 0, 300, 100, 20, $CBS_DROPDOWNLIST)
GUICtrlSetData($idCombo, "AES (128bit)|AES (192bit)|AES (256bit)", "AES (128bit)")
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
GUISetState(@SW_SHOW, $hGUI)
_Crypt_Startup() ; To optimize performance start the crypt library.
_Crypt_DestroyKey($g_hKey) ; Destroy the cryptographic key.
;~ $g_hKey = _Crypt_DeriveKey("CryptPassword", $iAlgorithm) ; Re-declare a password string and algorithm to create a new cryptographic key.
$iAlgorithm = $CALG_AES_128
$g_hKey = _Crypt_DeriveKey("Z_h$W@123", $iAlgorithm)
Local $sRead = GUICtrlRead($g_idInputEdit)
If StringStripWS($sRead, $STR_STRIPALL) <> "" Then ; Check there is text available to encrypt.
Local $bEncrypted = _Crypt_EncryptData($sRead, $g_hKey, $CALG_USERKEY) ; Encrypt the text with the new cryptographic key.
GUICtrlSetData($g_idOutputEdit, Base64($bEncrypted)) ; Set the output box with the encrypted text.
EndIf
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
Exit
Case $idCombo ; Check when the combobox is selected and retrieve the correct algorithm.
Switch GUICtrlRead($idCombo) ; Read the combobox selection.
Case "AES (128bit)"
$iAlgorithm = $CALG_AES_128
Case "AES (192bit)"
$iAlgorithm = $CALG_AES_192
Case "AES (256bit)"
$iAlgorithm = $CALG_AES_256
EndSwitch
EndSwitch
WEnd
GUIDelete($hGUI) ; Delete the previous GUI and all controls.
_Crypt_DestroyKey($g_hKey) ; Destroy the cryptographic key.
_Crypt_Shutdown() ; Shutdown the crypt library.
EndFunc ;==>Example
Func Base64($vCode, $bEncode = True, $bUrl = False)
Local $oDM = ObjCreate("Microsoft.XMLDOM")
If Not IsObj($oDM) Then Return SetError(1, 0, 1)
Local $oEL = $oDM.createElement("Tmp")
$oEL.DataType = "bin.base64"
If $bEncode Then
$oEL.NodeTypedValue = Binary($vCode)
If Not $bUrl Then Return $oEL.Text
Return StringReplace(StringReplace(StringReplace($oEL.Text, "+", "-"), "/", "_"), @LF, "")
Else
If $bUrl Then $vCode = StringReplace(StringReplace($vCode, "-", "+"), "_", "/")
$oEL.Text = $vCode
Return $oEL.NodeTypedValue
EndIf
EndFunc ;==>Base64
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
#forceref $hWnd, $iMsg, $lParam
Switch _WinAPI_LoWord($wParam)
Case $g_idInputEdit
Switch _WinAPI_HiWord($wParam)
Case $EN_CHANGE
Local $bEncrypted = _Crypt_EncryptData(GUICtrlRead($g_idInputEdit), $g_hKey, $CALG_USERKEY) ; Encrypt the text with the cryptographic key.
GUICtrlSetData($g_idOutputEdit, Base64($bEncrypted)) ; Set the output box with the encrypted text.
EndSwitch
EndSwitch
EndFunc ;==>WM_COMMAND
以下为该函数的C#DLL,因无接口本想通过regasm注册再用au3调用,但注册失败:
#PRE_UseX64=n
#RequireAdmin
Global $dll = 'Inhua.Silverlight.Common.dll'
Global $RegAsm = @ScriptDir & '\regasm.exe'
Local $obj = regdll()
Func regdll()
Local $obj = ObjCreate("Inhua.Silverlight.Common.Cryptography")
If Not IsObj($obj) Then
;~ RunWait($RegAsm & " /codebase " & $dll, @ScriptDir, @SW_HIDE) ; register the .net DLL
$obj = ObjCreate("Inhua.Silverlight.Common.Cryptography")
If Not IsObj($obj) Then
MsgBox(0, @error, '注册失败')
Exit
EndIf
EndIf
Return $obj
EndFunc ;==>regdll
如果能成功Obj调用就是最简单的解决方法了,故附上dll,望熟悉加密算法的坛友指点迷津,感激不尽!
亦可参考本文:https://blog.csdn.net/kangrydotnet/article/details/43987835(c#爬取Silverlight网页)此文解决思路基本符合。
本帖最后由 autoit3CN 于 2019-12-8 23:49 编辑
http://zayko.net/post/How-to-Enc ... for-Windows-Phone-7
《How to Encrypt/Decrypt a String in Silverlight 》此文即正文提问的加解密算法https://blog.csdn.net/xuyue1987/article/details/6706600
《Silverlight信息加密 - 通过Rfc2898DeriveBytes类使用基于HMACSHA1的伪随机数生成器实现PBKDF2》
https://blog.csdn.net/bohemianlife/article/details/8433017
《Silverlight中的字符串常用加解密》
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace UI.Common
{
public class Encrypt
{
/// <summary>
/// 通过用户提供的密码加密字符串
/// </summary>
/// <param name="input">要加密的字符串</param>
/// <param name="password">要用于加密的字符串</param>
/// <returns>加密后的字符串</returns>
public static string Encrypt(string input, string password)
{
string data = input;
byte[] utfdata = UTF8Encoding.UTF8.GetBytes(data);
byte[] saltBytes = UTF8Encoding.UTF8.GetBytes(password);
// 对称加密技术 高级加密标准(AES) 对称算法的管理类
AesManaged aes = new AesManaged();
// 使用 PBKDF2 标准 密码加密技术
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, saltBytes);
// 设置参数
/*
AesManaged.BlockSize - 加密操作的块大小(单位:bit)
AesManaged.LegalBlockSizes - 对称算法支持的块大小(单位:bit)
AesManaged.KeySize - 对称算法的密钥大小(单位:bit)
AesManaged.LegalKeySizes - 对称算法支持的密钥大小(单位:bit)
AesManaged.Key - 对称算法的密钥
AesManaged.IV - 对称算法的密钥大小
Rfc2898DeriveBytes.GetBytes(int 需要生成的伪随机密钥字节数) - 生成密钥
*/
aes.BlockSize = aes.LegalBlockSizes.MaxSize;
aes.KeySize = aes.LegalKeySizes.MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = rfc.GetBytes(aes.BlockSize / 8);
// 加密 用当前的 Key 属性和初始化向量 IV 创建对称加密器对象
ICryptoTransform encryptTransf = aes.CreateEncryptor();
// 输出流,可用于文件流
MemoryStream encryptStream = new MemoryStream();
CryptoStream encryptor = new CryptoStream(encryptStream, encryptTransf, CryptoStreamMode.Write);
// 将一个字节序列写入当前 CryptoStream (完成加密的过程)
encryptor.Write(utfdata, 0, utfdata.Length);
encryptor.Flush();
encryptor.Close();
byte[] encryptBytes = encryptStream.ToArray();
// 将加密后所得到的流转换成字节数组,再用Base64编码将其转换为字符串
string encryptedString = Convert.ToBase64String(encryptBytes);
return encryptedString;
}
/// <summary>
/// 通过用户提供的密码解密字符串
/// </summary>
/// <param name="base64Input">待解密的字符串</param>
/// <param name="password">用于解密的密码</param>
/// <returns>解密后的字符串</returns>
public static string Decrypt(string base64Input, string password)
{
byte[] encryptBytes = Convert.FromBase64String(base64Input);
byte[] saltBytes = Encoding.UTF8.GetBytes(password);
// 对称加解密技术
AesManaged aes = new AesManaged();
// 使用 PBKDF2 标准 密码加密技术
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, saltBytes);
// 设置参数
aes.BlockSize = aes.LegalBlockSizes.MaxSize;
aes.KeySize = aes.LegalKeySizes.MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = rfc.GetBytes(aes.BlockSize / 8);
// 开始解密
ICryptoTransform decryptTrans = aes.CreateDecryptor();
// 解密后的输出流
MemoryStream decryptStream = new MemoryStream();
CryptoStream decryptor = new CryptoStream(decryptStream, decryptTrans, CryptoStreamMode.Write);
// 将一个字节序列写入当前 CryptoStream (完成解密的过程)
decryptor.Write(encryptBytes, 0, encryptBytes.Length);
decryptor.Flush();
decryptor.Close();
// 将解密后所得到的流转换为字符串
byte[] decryptBytes = decryptStream.ToArray();
string decryptedString = UTF8Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
return decryptedString;
}
}
}
本帖最后由 autoit3CN 于 2019-12-9 16:21 编辑
input=BBBBBB|123456
SecretKey Password = "Z_h$W@123";
SecretKey Salt = "123@Z_h$W";
究竟怎样填写才可以得到和Cryptography.AesEncrypt同样的结果:dn78uzHKtqCh936l0fbQ4A==
https://www.it399.com/aes
http://tool.chacuo.net/cryptaes
https://the-x.cn/cryptography/Aes.aspx
本帖最后由 autoit3CN 于 2019-12-9 16:52 编辑
AES算法我看别人设置参数的KEY和IV有些十六进制的,C#那个源代码硬着头皮看了好久,在PBKDF2算法就搞迷糊了:
// Rfc2898DeriveBytes - 通过使用基于 HMACSHA1 的伪随机数生成器,实现基于密码的密钥派生功能 (PBKDF2 - 一种基于密码的密钥派生函数)
// 通过 密码 和 salt 派生密钥
System.Security.Cryptography.Rfc2898DeriveBytes rfc = new System.Security.Cryptography.Rfc2898DeriveBytes(pwdValue, salt);
/**/
/*
* AesManaged.BlockSize - 加密操作的块大小(单位:bit)
* AesManaged.LegalBlockSizes - 对称算法支持的块大小(单位:bit)
* AesManaged.KeySize - 对称算法的密钥大小(单位:bit)
* AesManaged.LegalKeySizes - 对称算法支持的密钥大小(单位:bit)
* AesManaged.Key - 对称算法的密钥
* AesManaged.IV - 对称算法的密钥大小</font>
* Rfc2898DeriveBytes.GetBytes(int 需要生成的伪随机密钥字节数) - 生成密钥
*/
Rfc2898DeriveBytes会对口令和盐进行加密,通过GetBytes方法得到为随机密匙,将2个为随机密匙设置为AES中的key和iv
bytes.GetBytes(managed.get_KeySize() / 8)
bytes.GetBytes(managed.get_BlockSize() / 8)
看了一头雾水,帮顶一下,等大神来帮忙 尝试AES JS调用方式思路,未果:function aes_encrypt(text) {
var key = 'd49d691f234441add2f610d5d11f6aad';
key = CryptoJS.enc.Utf8.parse(key);
var iv = "b883b5ec8ca259692869ada4b72dc6f5";
iv = CryptoJS.enc.Utf8.parse(iv);
var encrypted = CryptoJS.AES.encrypt(text, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
}).toString();
return encrypted;
};
找了几个AES加密的js,不带salt的标准AES是可以加密的,但是带salt的反复调试还是无法接近目标:
附带js库:
挖地三尺在官网找到了一个cryptong-UDF(https://www.autoitscript.com/forum/files/file/490-cryptong-udf-cryptography-api-next-generation/),一看有封装函数:_CryptoNG_PBKDF2($sPassword, $vSalt, $iIterations, $iDKeyBitLength, $sHashAlgorithmId = $CNG_BCRYPT_SHA1_ALGORITHM, $sProvider = "Microsoft Primitve Provider")
感觉有戏,尝试调试:
#include <Constants.au3>
#include "CryptoNG.au3"
#include <Debug.au3>
aes_encrypt_decrypt_example2()
Func aes_encrypt_decrypt_example2()
Const $MESSAGE = "BBBBBB|123456", _
$SECRET = "Z_h$W@123", _
$SECRET_SALT= "123@Z_h$W"
Local $sAlgId = "", $sDecryptedMessage = ""
Local $vEncryptKey = ""
Local $xEncryptedMessage = ""
$sAlgId = $CNG_BCRYPT_AES_ALGORITHM
;Create a hashed encryption key from text-based password/salt
$vEncryptKey = _CryptoNG_PBKDF2($SECRET, $SECRET_SALT, 1000,$CNG_KEY_BIT_LENGTH_AES_128, $CNG_BCRYPT_SHA1_ALGORITHM)
If @error Then
ConsoleWrite("ERROR: " & _CryptoNG_LastErrorMessage() & @CRLF)
Exit 1
EndIf
;Encrypt plain text message
$xEncryptedMessage = _CryptoNG_EncryptData($sAlgId, $MESSAGE, $vEncryptKey)
If @error Then
ConsoleWrite("ERROR: " & _CryptoNG_LastErrorMessage() & @CRLF)
Exit 1
EndIf
;Decrypt encrypted message
$sDecryptedMessage = _CryptoNG_DecryptData($sAlgId, $xEncryptedMessage, $vEncryptKey)
If @error Then
ConsoleWrite("ERROR: " & _CryptoNG_LastErrorMessage() & @CRLF)
Exit 1
EndIf
ConsoleWrite(@CRLF)
ConsoleWrite(StringFormat("CryptoNG UDF Version %s", _CryptoNG_Version()) & @CRLF)
ConsoleWrite(StringFormat("%s Plain text message = %s", $sAlgId, $MESSAGE) & @CRLF)
ConsoleWrite(StringFormat("%s Encrypt Key = %s", $sAlgId, $SECRET) & @CRLF)
ConsoleWrite(StringFormat("%s Encrypt Key Salt = %s", $sAlgId, $SECRET_SALT) & @CRLF)
ConsoleWrite(StringFormat("%s Encrypt Key (Hashed) = %s", $sAlgId, Base64($vEncryptKey)) & @CRLF)
ConsoleWrite(StringFormat("%s Encrypted Message = %s", $sAlgId,Base64($xEncryptedMessage)) & @CRLF)
ConsoleWrite(StringFormat("%s Decrypted Message = %s", $sAlgId, $sDecryptedMessage) & @CRLF)
EndFunc
Func Base64($vCode, $bEncode = True, $bUrl = False)
Local $oDM = ObjCreate("Microsoft.XMLDOM")
If Not IsObj($oDM) Then Return SetError(1, 0, 1)
Local $oEL = $oDM.createElement("Tmp")
$oEL.DataType = "bin.base64"
If $bEncode Then
$oEL.NodeTypedValue = Binary($vCode)
If Not $bUrl Then Return $oEL.Text
Return StringReplace(StringReplace(StringReplace($oEL.Text, "+", "-"), "/", "_"), @LF, "")
Else
If $bUrl Then $vCode = StringReplace(StringReplace($vCode, "-", "+"), "_", "/")
$oEL.Text = $vCode
Return $oEL.NodeTypedValue
EndIf
EndFunc ;==>Base64调试加密结果:
CryptoNG UDF Version 1.1.1
AES Plain text message = BBBBBB|123456
AES Encrypt Key = Z_h$W@123
AES Encrypt Key Salt = 123@Z_h$W
AES Encrypt Key (Hashed) = kJQkmJBeaAHHxMzwd18WTw==
AES Encrypted Message = Ch3KWLH+OEc8uK7MXVVg3A==
AES Decrypted Message = BBBBBB|123456和我想要的C#AesEncrypt加密结果:dn78uzHKtqCh936l0fbQ4A==还是有差异
但是反复看CryptoNG-UDF的代码思路,感觉方向是越来越近了,继续研究...
AES在日常应用还是非常广的,甚至那些加密勒索病毒就是用AES256位高强度加密的(譬如Hakbit勒索病毒:https://mp.weixin.qq.com/s/bQPJ48gL7IQPRMPGC1CuXw)
值得大家认真研究,可惜中文论坛和英文论坛的带salt128位CBC加密相关资料不多,网络上的大多是c#、java、net、js版本的,调用起来也是各种坑,
如没有类似我的特定需求,楼上这个CryptoNG UDF应该可以满足普通加密自用了。 C# 封装为库,dllcall方式调用 应该可以 虫子樱桃 发表于 2019-12-30 12:20
C# 封装为库,dllcall方式调用 应该可以
谢谢,最后还是通过nodejs和CryptoJS解决了。
页:
[1]