侧边栏壁纸
博主头像
komi

Bona Fides

  • 累计撰写 11 篇文章
  • 累计创建 20 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

API对接中的解密 3DES/TDEA

komi
2024-11-02 / 0 评论 / 0 点赞 / 45 阅读 / 1,567 字

起因

和三方对接客户录入接口 发现对方输入的参数竟然是加密后的密文 需要用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

cipherText=Ek3(Dk2(Ek1(plainText)))cipherText = E_k3(D_k2(E_k1(plainText)))

相反地 解密就是 Decryption Encryption Decryption 也是三次计算

plainText=Dk1(Ek2(Dk3(cipherText)))plainText = D_k1(E_k2(D_k3(cipherText)))

这三次计算使用的密钥均相等时 前两步可以相互抵消 只有在最后一步是在做加/解密计算 这也兼容了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); 可以从实现类中看到

TripleDES

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;
    }
  }
}

TripleDesImplementation

    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 对应着三轮计算的密钥

0

评论区