起因
和三方对接客户录入接口 发现对方输入的参数竟然是加密后的密文 需要用3DESEDE或者是AES来解密
发现系统里原先没有3DESEDE的加解密方法(毕竟被更安全也更快的AES已经替代了) 那我最好是自己写一个以备后患
熟悉概念
In cryptography, Triple DES (3DES or TDES), officially the Triple Data Encryption Algorithm (TDEA or Triple DEA), is a symmetric-key block cipher, which applies the DES cipher algorithm three times to each data block.
3DES/TDEA 是一种对称加密 衍生自DES 也就意味着可以兼容DES
EDE实际上就是 对应着三次计算 Encryption Decryption Encryption
相反地 解密就是 Decryption Encryption Decryption 也是三次计算
这三次计算使用的密钥均相等时 前两步可以相互抵消 只有在最后一步是在做加/解密计算 这也兼容了DES的算法 3DES的特点就是让密钥的长度更长 更加难以暴力破解
Code
/// <summary>
/// DES-EDE 加密
/// </summary>
/// <param name="plainText">明文</param>
/// <param name="key">密钥</param>
/// <param name="iv">初始向量</param>
/// <returns></returns>
public static string EncryptTriDesede(string plainText, string key, string iv)
{
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
var keyArray = Encoding.UTF8.GetBytes(key); // 直接读取key的字节数组
Array.Resize(ref keyArray, 192 / 8);
var ivArray = Encoding.UTF8.GetBytes(iv);// 直接读取IV的字节数组
using var algo = new TripleDESCryptoServiceProvider
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
using var encryptor = algo.CreateEncryptor(keyArray, ivArray);
var cipherBytes = encryptor.TransformFinalBlock(plainTextBytes, 0, plainTextBytes.Length);
return Convert.ToBase64String(cipherBytes);
}
/// <summary>
/// DES-EDE 解密
/// </summary>
/// <param name="cipherText">密文</param>
/// <param name="key">密钥</param>
/// <param name="iv">向量</param>
/// <returns></returns>
public static string DecryptTriDESEDE(string cipherText, string key, string iv)
{
// 需先Base64解码
var cipherTextBytes = Convert.FromBase64String(cipherText);
var keyArray = Encoding.UTF8.GetBytes(key); // 直接读取key的字节数组
Array.Resize(ref keyArray, 192 / 8);
var ivArray = Encoding.UTF8.GetBytes(iv);// 直接读取IV的字节数组
using var algo = new TripleDESCryptoServiceProvider
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
using var decryptor = algo.CreateDecryptor(keyArray, ivArray);
var plainBytes = decryptor.TransformFinalBlock(cipherTextBytes, 0, cipherTextBytes.Length);
return Encoding.UTF8.GetString(plainBytes);
}
可以看到.net中有对应的实现类 (实际上也是包装了下)
TripleDESCryptoServiceProvider
[Obsolete("Derived cryptographic types are obsolete. Use the Create method on the base type instead.", DiagnosticId = "SYSLIB0021", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class TripleDESCryptoServiceProvider : TripleDES
{
#nullable disable
private readonly TripleDES _impl;
/// <summary>Initializes a new instance of the <see cref="T:System.Security.Cryptography.TripleDESCryptoServiceProvider" /> class.</summary>
/// <exception cref="T:System.Security.Cryptography.CryptographicException">The <see cref="T:System.Security.Cryptography.TripleDES" /> cryptographic service provider is not available.</exception>
public TripleDESCryptoServiceProvider() => this._impl = TripleDES.Create();
...
}
至于我为什么写 Array.Resize(ref keyArray, 192 / 8);
可以从实现类中看到
using Internal.Cryptography;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Versioning;
#nullable enable
namespace System.Security.Cryptography
{
/// <summary>Represents the base class for Triple Data Encryption Standard algorithms from which all <see cref="T:System.Security.Cryptography.TripleDES" /> implementations must derive.</summary>
public abstract class TripleDES : SymmetricAlgorithm
{
#nullable disable
private static readonly KeySizes[] s_legalBlockSizes = new KeySizes[1]
{
new KeySizes(64, 64, 0)
};
private static readonly KeySizes[] s_legalKeySizes = new KeySizes[1]
{
new KeySizes(128, 192, 64)
};
/// <summary>Initializes a new instance of the <see cref="T:System.Security.Cryptography.TripleDES" /> class.</summary>
protected TripleDES()
{
this.KeySizeValue = 192;
this.BlockSizeValue = 64;
this.FeedbackSizeValue = this.BlockSizeValue;
this.LegalBlockSizesValue = TripleDES.s_legalBlockSizes.CloneKeySizesArray();
this.LegalKeySizesValue = TripleDES.s_legalKeySizes.CloneKeySizesArray();
}
#nullable enable
/// <summary>Creates an instance of a cryptographic object to perform the <see cref="T:System.Security.Cryptography.TripleDES" /> algorithm.</summary>
/// <returns>An instance of a cryptographic object.</returns>
[UnsupportedOSPlatform("browser")]
public static TripleDES Create() => (TripleDES) new TripleDesImplementation();
/// <summary>Creates an instance of a cryptographic object to perform the specified implementation of the <see cref="T:System.Security.Cryptography.TripleDES" /> algorithm.</summary>
/// <param name="str">The name of the specific implementation of <see cref="T:System.Security.Cryptography.TripleDES" /> to use.</param>
/// <returns>An instance of a cryptographic object.</returns>
[Obsolete("Cryptographic factory methods accepting an algorithm name are obsolete. Use the parameterless Create factory method on the algorithm type instead.", DiagnosticId = "SYSLIB0045", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
[RequiresUnreferencedCode("The default algorithm implementations might be removed, use strong type references like 'RSA.Create()' instead.")]
public static TripleDES? Create(string str) => (TripleDES) CryptoConfig.CreateFromName(str);
/// <summary>Gets or sets the secret key for the <see cref="T:System.Security.Cryptography.TripleDES" /> algorithm.</summary>
/// <exception cref="T:System.ArgumentNullException">An attempt was made to set the key to <see langword="null" />.</exception>
/// <exception cref="T:System.Security.Cryptography.CryptographicException">An attempt was made to set a key whose length is invalid.
///
/// -or-
///
/// An attempt was made to set a weak key (see <see cref="M:System.Security.Cryptography.TripleDES.IsWeakKey(System.Byte[])" />).</exception>
/// <returns>The secret key for the <see cref="T:System.Security.Cryptography.TripleDES" /> algorithm.</returns>
public override byte[] Key
{
get
{
byte[] key;
for (key = base.Key; TripleDES.IsWeakKey(key); key = base.Key)
this.GenerateKey();
return key;
}
set
{
ArgumentNullException.ThrowIfNull((object) value, nameof (value));
if (!(value.Length * 8).IsLegalSize(TripleDES.s_legalKeySizes))
throw new ArgumentException(SR.Cryptography_InvalidKeySize);
base.Key = !TripleDES.IsWeakKey(value) ? value : throw new CryptographicException(SR.Format(SR.Cryptography_InvalidKey_Weak, (object) nameof (TripleDES)));
}
}
/// <summary>Determines whether the specified key is weak.</summary>
/// <param name="rgbKey">The secret key to test for weakness.</param>
/// <exception cref="T:System.Security.Cryptography.CryptographicException">The size of the <paramref name="rgbKey" /> parameter is not valid.</exception>
/// <returns>
/// <see langword="true" /> if the key is weak; otherwise, <see langword="false" />.</returns>
public static bool IsWeakKey(byte[] rgbKey)
{
if (rgbKey == null)
throw new CryptographicException(SR.Cryptography_InvalidKeySize);
if (!(rgbKey.Length * 8).IsLegalSize(TripleDES.s_legalKeySizes))
throw new CryptographicException(SR.Cryptography_InvalidKeySize);
byte[] rgbKey1 = rgbKey.FixupKeyParity();
return TripleDES.EqualBytes(rgbKey1, 0, 8, 8) || rgbKey1.Length == 24 && TripleDES.EqualBytes(rgbKey1, 8, 16, 8);
}
#nullable disable
private static bool EqualBytes(byte[] rgbKey, int start1, int start2, int count)
{
for (int index = 0; index < count; ++index)
{
if ((int) rgbKey[start1 + index] != (int) rgbKey[start2 + index])
return false;
}
return true;
}
}
}
private UniversalCryptoTransform CreateTransform(byte[] rgbKey, byte[] rgbIV, bool encrypting)
{
ArgumentNullException.ThrowIfNull((object) rgbKey, nameof (rgbKey));
long size = (long) rgbKey.Length * 8L;
if (size > (long) int.MaxValue || !((int) size).IsLegalSize(this.LegalKeySizes))
throw new ArgumentException(SR.Cryptography_InvalidKeySize, nameof (rgbKey));
if (rgbIV != null && (long) rgbIV.Length * 8L != (long) this.BlockSize)
throw new ArgumentException(SR.Cryptography_InvalidIVSize, nameof (rgbIV));
if (rgbKey.Length == 16)
{
byte[] destinationArray = new byte[24];
Array.Copy((Array) rgbKey, (Array) destinationArray, 16);
Array.Copy((Array) rgbKey, 0, (Array) destinationArray, 16, 8);
rgbKey = destinationArray;
}
if (this.Mode == CipherMode.CFB)
TripleDesImplementation.ValidateCFBFeedbackSize(this.FeedbackSize);
return TripleDesImplementation.CreateTransformCore(this.Mode, this.Padding, rgbKey, rgbIV, this.BlockSize / 8, this.GetPaddingSize(this.Mode, this.FeedbackSize), this.FeedbackSize / 8, encrypting);
}
这里的192 8 都是bit(比特) 192 / 8 得到 24bit 也就是3byte 对应着三轮计算的密钥
评论区