C# AES CTR模式 CryptoJS 对应C# .NET写法
吐槽下国内博客基本都是瞎几把转发,找了2天没找到正确的方式,都准备放弃,使用WebBrowser 来跑
CryptoJS.AES.decrypt({ciphertext: CryptoJS.enc.Base64.parse("79VrqFVhnPb36ZbAP0DZlA==")},CryptoJS.enc.Latin1.parse("442A472D4B6150645267556B58703273"),{mode:CryptoJS.mode.CTR,iv:CryptoJS.enc.Latin1.parse("556A586E32723575"),padding: CryptoJS.pad.Pkcs7}).toString(CryptoJS.enc.Utf8);
javascript解析出来明文是:hello
// The MIT License (MIT) // Copyright (c) 2014 Hans Wolff // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Collections.Generic; using System.Security.Cryptography; public class Aes128CounterMode : SymmetricAlgorithm { private readonly byte[] _counter; private readonly AesManaged _aes; public Aes128CounterMode(byte[] counter) { if (counter == null) throw new ArgumentNullException("counter"); if (counter.Length != 16) throw new ArgumentException(String.Format("Counter size must be same as block size (actual: {0}, expected: {1})", counter.Length, 16)); _aes = new AesManaged { Mode = CipherMode.ECB, Padding = PaddingMode.None }; _counter = counter; } public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] ignoredParameter) { return new CounterModeCryptoTransform(_aes, rgbKey, _counter); } public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] ignoredParameter) { return new CounterModeCryptoTransform(_aes, rgbKey, _counter); } public override void GenerateKey() { _aes.GenerateKey(); } public override void GenerateIV() { // IV not needed in Counter Mode } } public class CounterModeCryptoTransform : ICryptoTransform { private readonly byte[] _counter; private readonly ICryptoTransform _counterEncryptor; private readonly Queue<byte> _xorMask = new Queue<byte>(); private readonly SymmetricAlgorithm _symmetricAlgorithm; public CounterModeCryptoTransform(SymmetricAlgorithm symmetricAlgorithm, byte[] key, byte[] counter) { if (symmetricAlgorithm == null) throw new ArgumentNullException("symmetricAlgorithm"); if (key == null) throw new ArgumentNullException("key"); if (counter == null) throw new ArgumentNullException("counter"); if (counter.Length != symmetricAlgorithm.BlockSize / 8) throw new ArgumentException(String.Format("Counter size must be same as block size (actual: {0}, expected: {1})", counter.Length, symmetricAlgorithm.BlockSize / 8)); _symmetricAlgorithm = symmetricAlgorithm; _counter = counter; var zeroIv = new byte[_symmetricAlgorithm.BlockSize / 8]; _counterEncryptor = symmetricAlgorithm.CreateEncryptor(key, zeroIv); } public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { var output = new byte[inputCount]; TransformBlock(inputBuffer, inputOffset, inputCount, output, 0); return output; } public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { for (var i = 0; i < inputCount; i++) { if (NeedMoreXorMaskBytes()) EncryptCounterThenIncrement(); var mask = _xorMask.Dequeue(); outputBuffer[outputOffset + i] = (byte)(inputBuffer[inputOffset + i] ^ mask); } return inputCount; } private bool NeedMoreXorMaskBytes() { return _xorMask.Count == 0; } private void EncryptCounterThenIncrement() { var counterModeBlock = new byte[_symmetricAlgorithm.BlockSize / 8]; _counterEncryptor.TransformBlock(_counter, 0, _counter.Length, counterModeBlock, 0); IncrementCounter(); foreach (var b in counterModeBlock) { _xorMask.Enqueue(b); } } private void IncrementCounter() { for (var i = _counter.Length - 1; i >= 0; i--) { if (++_counter[i] != 0) break; } } public int InputBlockSize { get { return _symmetricAlgorithm.BlockSize / 8; } } public int OutputBlockSize { get { return _symmetricAlgorithm.BlockSize / 8; } } public bool CanTransformMultipleBlocks { get { return true; } } public bool CanReuseTransform { get { return false; } } public void Dispose() { } }
using RGiesecke.DllExport; using System; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; namespace AES_CTR_NET { [ComVisible(true)] [Guid("8871C5E0-B296-4AB8-AEE7-F2553BACB730"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IAES_CTR { [return: MarshalAs(UnmanagedType.I4)] int Encripta(string base64Data, string base64Llave, [MarshalAs(UnmanagedType.BStr)] out string base64Resultado); [return: MarshalAs(UnmanagedType.I4)] int Desencripta(string base64Data, string base64Llave, [MarshalAs(UnmanagedType.BStr)] out string base64Resultado); [return: MarshalAs(UnmanagedType.BStr)] string GetID(); void SetID(string v); [return: MarshalAs(UnmanagedType.BStr)] string Version(); } public class AES_CTR : IAES_CTR { private string _VERSION_ = "1.0.0.1"; static private string _S_VERSION_ = "1.0.0.1"; public string Version() { return this._VERSION_; } public string ID { get; set; } public void SetID(string v) { ID = v; } public string GetID() { return ID; } /// <summary> /// Encripta un valor en AES_CTR /// </summary> /// <param name="base64Data">Cadena de texto en Base64 a encriptar</param> /// <param name="llave">Llave en claro</param> /// <param name="resultado">Cadena de texto en Base64 obtenida del arreglo de bytes</param> /// <returns> Cantidad de Bytes obtenido al encriptar</returns> public int Encripta(string base64Data, string llave, out string base64Resultado) { int result = -1; base64Resultado = ""; byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; byte[] outData = null; byte[] llaveB = null; byte[] data = null; try { #region Validaciones try { Encoding.UTF8.GetString(Convert.FromBase64String(base64Data)); } catch (Exception) { throw new Exception(string.Format("La data a encriptar NO es un Base64 Valido [{0}]", base64Data)); } try { Encoding.UTF8.GetString(Convert.FromBase64String(llave)); } catch (Exception) { throw new Exception(string.Format("La llave NO es un Base64 Valido [{0}]", llave)); } #endregion data = Encoding.UTF8.GetBytes(base64Data); outData = new byte[base64Data.Length]; llaveB = Encoding.UTF8.GetBytes(llave);// Convert.FromBase64String(base64Llave); Aes128CounterMode am = new Aes128CounterMode(iv); ICryptoTransform ict = am.CreateEncryptor(llaveB, null); ict.TransformBlock(data, 0, outData.Length, outData, 0); base64Resultado = Convert.ToBase64String(outData); result = outData.Length; } catch (Exception e) { base64Resultado = e.Message; } return result; } /// <summary> /// <summary> /// Encripta un valor en AES_CTR /// </summary> /// <param name="data">Cadena de texto en Base64 a encriptar</param> /// <param name="llave">Llave en claro</param> /// <param name="resultado">Cadena de texto en Base64 obtenida del arreglo de bytes</param> /// <returns> Cantidad de Bytes obtenido al encriptar</returns> public int Encripta(byte[] data, byte[] llave, out byte[] resultado) { int result = -1; byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; resultado = null; try { resultado = new byte[data.Length]; Aes128CounterMode am = new Aes128CounterMode(iv); ICryptoTransform ict = am.CreateEncryptor(llave, null); ict.TransformBlock(data, 0, resultado.Length, resultado, 0); result = resultado.Length; } catch (Exception e) { resultado = Encoding.UTF8.GetBytes(e.Message); } return result; } /// <summary> /// Desencripta un valor en AES_CTR /// </summary> /// <param name="base64Data">Data Encriptada</param> /// <param name="llave">Llave en claro</param> /// <param name="resultado">Cadena de texto obtenida del arreglo de bytes</param> /// <returns> Cantidad de Bytes obtenido al desencriptar </returns> public int Desencripta(string base64Data, string llave, out string resultado) { int result = -1; resultado = ""; byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; byte[] outData = null; byte[] llaveB = null; byte[] data = null; try { #region Validaciones try { Encoding.UTF8.GetString(Convert.FromBase64String(base64Data)); } catch (Exception) { throw new Exception(string.Format("La data a desencriptar NO es un Base64 Valido [{0}]", base64Data)); } try { Encoding.UTF8.GetString(Convert.FromBase64String(llave)); } catch (Exception) { throw new Exception(string.Format("La llave NO es un Base64 Valido [{0}]", llave)); } #endregion data = Convert.FromBase64String(base64Data); outData = new byte[data.Length]; llaveB = Encoding.UTF8.GetBytes(llave);// Convert.FromBase64String(base64Llave); Aes128CounterMode am = new Aes128CounterMode(iv); ICryptoTransform ict = am.CreateDecryptor(llaveB, null); ict.TransformBlock(data, 0, data.Length, outData, 0); resultado = Encoding.UTF8.GetString(outData); result = outData.Length; } catch (Exception e) { resultado = e.Message; } return result; } /// <summary> /// Desencripta un valor en AES_CTR /// </summary> /// <param name="dataIn">Data Encriptada</param> /// <param name="llave">Arreglo de bytes (32 bytes)</param> /// <param name="resultado">Cadena de texto obtenida del arreglo de bytes</param> /// <returns> Cantidad de Bytes obtenido al desencriptar </returns> public int Desencripta(byte[] data, byte[] llave,byte[] iv, out byte[] resultado) { int result = -1; resultado = null; try { resultado = new byte[data.Length]; Aes128CounterMode am = new Aes128CounterMode(iv); ICryptoTransform ict = am.CreateDecryptor(llave, null); ict.TransformBlock(data, 0, data.Length, resultado, 0); result = resultado.Length; } catch (Exception e) { resultado = Encoding.UTF8.GetBytes(e.Message); } return result; } [DllExport(CallingConvention = CallingConvention.Cdecl)] public static void CreaObjeto([MarshalAs(UnmanagedType.Interface)] out IAES_CTR miAES) { miAES = new AES_CTR(); miAES.SetID("_UNDEF_"); } [DllExport("VersionNTS", CallingConvention = CallingConvention.Cdecl)] public static void VersionNTS([MarshalAs(UnmanagedType.BStr)] out string version) { version = _S_VERSION_; } [DllExport("EncriptaNTS", CallingConvention = CallingConvention.Cdecl)] public static int EncriptaNTS(IntPtr base64Data_P, IntPtr base64Llave_P, [MarshalAs(UnmanagedType.BStr)] out string base64Resultado) { string base64Data = Marshal.PtrToStringAuto(base64Data_P); string base64Llave = Marshal.PtrToStringAuto(base64Llave_P); var a = new AES_CTR(); var ok = a.Encripta(base64Data, base64Llave, out base64Resultado); a = null; return ok; } [DllExport("DesencriptaNTS", CallingConvention = CallingConvention.Cdecl)] public static int DesencriptaNTS(IntPtr base64Data_P, IntPtr base64Llave_P, [MarshalAs(UnmanagedType.BStr)] out string base64Resultado) { string base64Data = Marshal.PtrToStringAuto(base64Data_P); string base64Llave = Marshal.PtrToStringAuto(base64Llave_P); var a = new AES_CTR(); var ok = a.Desencripta(base64Data, base64Llave, out base64Resultado); a = null; return ok; } public static int EncriptaNTS(string base64Data, string base64Llave, out string base64Resultado) { var a = new AES_CTR(); var ok = a.Encripta(base64Data, base64Llave, out base64Resultado); a = null; return ok; } public static int DesencriptaNTS(string base64Data, string base64Llave, out string base64Resultado) { var a = new AES_CTR(); var ok = a.Desencripta(base64Data, base64Llave, out base64Resultado); a = null; return ok; } public static int DesencriptaNTS(byte[] base64Data, byte[] base64Llave, byte[] iv, out byte[] base64Resultado) { var a = new AES_CTR(); var ok = a.Desencripta(base64Data, base64Llave, iv, out base64Resultado); a = null; return ok; } } }
.CS源代码下载:
DEMO
AES_CTR_NET.AES_CTR.DesencriptaNTS(Convert.FromBase64String("79VrqFVhnPb36ZbAP0DZlA=="), System.Text.Encoding.UTF8.GetBytes("5A7234753778214125442A472D4B6150"), System.Text.Encoding.UTF8.GetBytes("556A586E32723575"), out resultbytes);