【问题标题】:AES Rijndael decryption C#AES Rijndael 解密 C#
【发布时间】:2023-03-23 21:09:01
【问题描述】:

我必须解密一些使用 AES256 Rijndael 加密发送的数据。 我有小伙伴用的加解密机制,是用JAVA开发的,不是很熟悉,但是用C#转置不了。

给我的密钥是 10 个字符长。

我认为下面的代码是可以的,除了 IV 计算。 您将首先找到 java 代码,然后是 C#:

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class UtilsCrypto {

    /* Rijndael/CFB8/NoPadding is default cipher */
    final static String CHIPHER = "Rijndael/CFB8/NoPadding";

    public static final String  MESSAGE_DIGEST_ALGORITHM    = "MD5";
    public static final String  AES                         = "AES";
    public static final String  AES_ECB_NO_PADDING          = "AES/ECB/NoPadding";

    private static byte[] md5(final String input) throws NoSuchAlgorithmException {
        final MessageDigest md = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM);
        return md.digest(input.getBytes());
    }

    private Cipher initCipher(final int mode, final String secretKey) throws Exception {
        final byte[] key = md5(secretKey);
        final byte[] iv = md5(secretKey);

        final SecretKeySpec skeySpec = new SecretKeySpec(key, AES);

        /* This valid with other ciphers than Rijndael/CFB8/NoPadding */
        // final IvParameterSpec initialVector = new IvParameterSpec(iv);

        /* Use this with Rijndael/CFB8/NoPadding */
        final IvParameterSpec initialVector = new IvParameterSpec(getIvBytes(iv));

        final Cipher cipher = Cipher.getInstance(CHIPHER);
        cipher.init(mode, skeySpec, initialVector);

        return cipher;
    }

    public String encrypt(final String dataToEncrypt, final String secretKey) {
        if (Utils.isEmpty(secretKey))
            return dataToEncrypt;

        String encryptedData = null;
        try {
            final Cipher cipher = initCipher(Cipher.ENCRYPT_MODE, secretKey);
            final byte[] encryptedByteArray = cipher.doFinal(dataToEncrypt.getBytes(Charset.forName("UTF8")));
            final BASE64Encoder enc = new BASE64Encoder();
            encryptedData = enc.encode(encryptedByteArray);
            encryptedData = encryptedData.replace("+", "-");
            encryptedData = encryptedData.replace("/", "_");
        } catch (Exception e) {
            System.err.println("Problem encrypting the data");
            e.printStackTrace();
        }

        return encryptedData;
    }

    public String decrypt(final String encryptedData, final String secretKey) {
        String decryptedData = null;
        String inData = encryptedData;
        try {
            final Cipher cipher = initCipher(Cipher.DECRYPT_MODE, secretKey);
            final BASE64Decoder dec = new BASE64Decoder();
            inData = inData.replace("-", "+");
            inData = inData.replace("_", "/");
            final byte[] encryptedByteArray = dec.decodeBuffer(inData); // ok
            final byte[] decryptedByteArray = cipher.doFinal(encryptedByteArray);
            decryptedData = new String(decryptedByteArray, "UTF8");
        } catch (Exception e) {
            System.err.println("Problem decrypting the data");
            e.printStackTrace();
        }
        return decryptedData;
    }

    /**
     * This method is only for Rijndael/CFB8/NoPadding
     * 
     * @param hashedKey
     *            md5
     * @return byte array
     * @throws Exception
     *             If any exceptions.
     */
     // on passe en arg le hash de la clé
    protected byte[] getIvBytes(byte[] hashedKey) throws Exception {
        byte[] inputBytes = new byte[16]; // init son tableau a 16 bytes
        final SecretKey key = new SecretKeySpec(hashedKey, AES); // secretKey
        final Cipher cipher = Cipher.getInstance(AES_ECB_NO_PADDING); 
        cipher.init(Cipher.ENCRYPT_MODE, key); // chiffre sa clé en AES avec un IV
        return cipher.doFinal(inputBytes);
    }
}

现在这是我迄今为止尝试过的:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Xml;
using System.Net;
using System.Web;
using System.Web.Services;
using Newtonsoft.Json;
using System.Security.Cryptography;
using System.Text;

namespace test
{
        public byte[] getIVBytes(byte[] hashedKey)
        {
            byte[] inputBytes = new byte[16];
            AesManaged tdes = new AesManaged();
            tdes.Key = hashedKey;
            tdes.Mode = CipherMode.ECB;
            tdes.BlockSize = 128;
            tdes.Padding = PaddingMode.None;
            ICryptoTransform crypt = tdes.CreateEncryptor();
            byte[] bla =  crypt.TransformFinalBlock(hashedKey, 0, inputBytes.Length);
            return bla;
        }

        [WebMethod]
        public string decrypt(String input, String key)
        {
            byte[] md5KeyHash;
            using (MD5 md5 = MD5.Create())
            {
                md5KeyHash = md5.ComputeHash(Encoding.UTF8.GetBytes(key));
            }
            input = input.Replace("-", "+");
            input = input.Replace("_", "/");
            input = input.Replace(" ", "");
            byte[] data = Convert.FromBase64String(input); // récupérer l'array de bytes du message chiffré encodé en b64
            String decrypted;
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Mode = CipherMode.CFB;
                rijAlg.BlockSize = 128;
                rijAlg.Padding = PaddingMode.None;
                rijAlg.Key = md5KeyHash;
                rijAlg.IV = getIVBytes(md5KeyHash);

                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, null);
                using (MemoryStream msDecrypt = new MemoryStream(data))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            decrypted = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
            return decrypted;
}

代码似乎是“正确的”,因为除此之外没有抛出任何错误: XML 错误分析:在文本内容中发现了一个无效字符。 在:http://localhost:55175/WebService1.asmx/decrypt 第 2 行,col44 :�Me����>m�H�ZԤ�af2ɾ`A�ٖ�H$�&/

我错过了什么?

【问题讨论】:

  • 数据作为 64 位字符串发送。使用 Convert.FromBase64String(string)。 java正在使用:final BASE64Decoder dec = new BASE64Decoder();
  • 我不是已经在用了吗?我的解密()函数的第 10 行?
  • 你能给出一些示例加密输入和解密输出吗?然后有人可以验证他们是否有工作代码。
  • 我错过了解码。该错误表明使用加密和解密时选项不同。请参阅下一页上的最后一个答案:stackoverflow.com/questions/9584167/…
  • 当然。清除输入:“这是一个测试”。加密输出:“1Wnhid6tqCv3cAlbIH4=”。我用java代码测试成功了。

标签: java c# encryption aes rijndael


【解决方案1】:

C#代码中存在一些错误:

  • getIVBytes-方法中,替换行

    byte[] bla = crypt.TransformFinalBlock(hashedKey, 0, inputBytes.Length);
    

    byte[] bla = crypt.TransformFinalBlock(inputBytes, 0, inputBytes.Length); // encrypt inputBytes
    
  • decrypt-方法中,在CreateDecryptor-调用之前添加

    rijAlg.FeedbackSize = 8; // Use CFB8
    

    并替换行

    ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, null);
    

    通过

    ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV); // Consider the IV
    

然后发布的密文可以用C#-code解密成发布的明文。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多