c# - 将 C# .Net 加密/解密算法迁移到 Ruby

标签 c# ruby-on-rails ruby encryption encryption-symmetric

我必须加密/解密来自使用以下代码(基于 Rijndael 算法)的基于 .Net 的 Web 服务的数据:

/**
 * Cifra una cadena texto con el algoritmo de Rijndael
 *
 * @param   plainMessage    mensaje plano (sin cifrar)
 * @param   p_strSpecialKey key especial
 * @return  string          texto cifrado en hexadecimal
 */
public static string AES_encryptString(String plainMessage, string p_strSpecialKey) {
  string strTxtEncrypt = "";

  // Crear una instancia del algoritmo de Rijndael
  try {
    Rijndael RijndaelAlg = Rijndael.Create();
    RijndaelAlg.KeySize = 128;
    RijndaelAlg.Mode = CipherMode.ECB;
    RijndaelAlg.Padding = PaddingMode.Zeros;

    byte[] Key = Encoding.UTF8.GetBytes(p_strSpecialKey);
    byte[] IV = RijndaelAlg.IV;

    int keySize = 32;
    Array.Resize(ref Key, keySize);

    // Establecer un flujo en memoria para el cifrado
    MemoryStream memoryStream = new MemoryStream();

    // Crear un flujo de cifrado basado en el flujo de los datos
    CryptoStream cryptoStream = new CryptoStream(memoryStream,
    RijndaelAlg.CreateEncryptor(Key, IV),
    CryptoStreamMode.Write);

    // Obtener la representación en bytes de la información a cifrar
    byte[] plainMessageBytes = Encoding.UTF8.GetBytes(plainMessage);

    // Cifrar los datos enviándolos al flujo de cifrado
    cryptoStream.Write(plainMessageBytes, 0, plainMessageBytes.Length);
    cryptoStream.FlushFinalBlock();

    // Obtener los datos datos cifrados como un arreglo de bytes
    byte[] cipherMessageBytes = memoryStream.ToArray();

    // Cerrar los flujos utilizados
    memoryStream.Close();
    cryptoStream.Close();

    strTxtEncrypt = ByteToHex(cipherMessageBytes);
  } catch (Exception ex) {
    AddToFile("Error al encriptar el valor: " + plainMessage + " con la clave especial: " + p_strSpecialKey + " " + ex.ToString());
  }

  return strTxtEncrypt;
}

/**
 * Descifra una cadena texto con el algoritmo de Rijndael
 *
 * @param   encryptedMessage    mensaje cifrado en hexadecimal
 * @param   p_strSpecialKey key especial
 * @return  string              texto descifrado (plano)
 */
public static string AES_decryptString(String encryptedMessage, string p_strSpecialKey) {
  string strDecrypt = "";

  // Crear una instancia del algoritmo de Rijndael
  try {
    Rijndael RijndaelAlg = Rijndael.Create();
    RijndaelAlg.KeySize = 128;
    RijndaelAlg.Mode = CipherMode.ECB;
    RijndaelAlg.Padding = PaddingMode.Zeros;

    byte[] Key = Encoding.UTF8.GetBytes(p_strSpecialKey);
    byte[] IV = RijndaelAlg.IV;

    int keySize = 32;
    Array.Resize(ref Key, keySize);

    // Obtener la representación en bytes del texto cifrado
    byte[] cipherTextBytes = HexToByteArray(encryptedMessage);

    // Crear un arreglo de bytes para almacenar los datos descifrados
    byte[] plainTextBytes = new byte[cipherTextBytes.Length];

    // Crear un flujo en memoria con la representación de bytes de la información cifrada
    MemoryStream memoryStream = new MemoryStream(cipherTextBytes);

    // Crear un flujo de descifrado basado en el flujo de los datos
    CryptoStream cryptoStream = new CryptoStream(memoryStream,
    RijndaelAlg.CreateDecryptor(Key, IV),
    CryptoStreamMode.Read);

    // Obtener los datos descifrados obteniéndolos del flujo de descifrado
    int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);

    // Cerrar los flujos utilizados
    memoryStream.Close();
    cryptoStream.Close();

    // Retornar la representación de texto de los datos descifrados
    strDecrypt = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).Replace("\0", "");
  } catch (Exception ex) {
    AddToFile("Error al desencriptar el valor: " + encryptedMessage + " con la clave especial: " + p_strSpecialKey + " " + ex.ToString());
  }

  return strDecrypt;
}

我研究了在 Ruby 上执行相同操作的方法,并找到了这个答案 ( How to decode Rijndael in ruby (encoded in VB.net) ),但它对我不起作用。另外,我不确定我必须为 iv 使用什么值。 Web 服务给我一个 token ,我必须将其用作 key (对此 100% 确定),但实际上我不知道我错过了什么。

我用于加密的代码是:

# /lib/crypt.rb
module Crypt
  ...
  def Crypt.encrypt(data, key, iv, cipher_type)
    aes = OpenSSL::Cipher::Cipher.new(cipher_type)
    aes.encrypt
    aes.key = key
    aes.iv = iv
    aes.update(data) + aes.final
  end
end

# ../ws.rb
...
token = "8c5d0e6b93cf5d38d7a076b2db35ee6d" #this is a one of the tokens i received
iv = token
Crypt.encrypt(a_serialized_json,token,iv,"AES-128-CBC")

The encrypted serialized json data that I have to send must be like a hexdigest string like this "f0997ddbb17b08913e00b6fb2541312c1cfdda85e555451a1832df076a5d4a5f7d81d8db92715eade144e9696dfbe9eea573baa8ea90cdbe5baadf32fdeb6db8c9ab6743f8eeeb508921999d7513fad3".但是链接上描述的方法会生成一个像这样的加密字符串 ""^w\x9A\x90B\xDC\f\x16\xB8\xBDt\xFBo\xD7r\x97""。

知道我做错了什么或遗漏了什么吗?

更新:我发现我得到的字符串输出是一个字节数组,我必须将这个字节数组转换为一个十六进制字符串。我正在使用以下方法 ( https://github.com/atomicobject/hex_string/blob/master/lib/hex_string.rb )。但是,仍然不确定 Cypher 是否已正确配置为充当 C# 代码。

最佳答案

最后,我找到了一个与 C# 代码完全匹配的库,它是 ruby-mcrypt ( https://github.com/kingpong/ruby-mcrypt )。我使用的加密/解密代码是这样的:

require 'mcrypt'

module Crypt
  def Crypt.m_encrypt(data, key)
    crypto = Mcrypt.new(:rijndael_128, :ecb, key, nil, :zeros)
    encrypted_data = crypto.encrypt(data)
    encrypted_data
  end

  def Crypt.m_decrypt(data, key)
    crypto = Mcrypt.new(:rijndael_128, :ecb, key, nil, :zeros)
    crypto.decrypt(data)
  end
end

重要提示:此 C# Rjandael 库不使用 IV,因此我将 nil 参数作为 IV 提供给 Mcrypt。

这只是加密/解密部分,我还将字符串转换为十六进制格式。希望它可以帮助别人!

关于c# - 将 C# .Net 加密/解密算法迁移到 Ruby,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30613033/

相关文章:

c# - MVVM的良好做法是在转换器中初始化StackPanel并使用ContentPresenter呈现吗?

ruby-on-rails - 致命 : Peer authentication failed for user "shop"

sql - 在 Rails 中,通过加在一起的两列进行查询?

ruby - 在没有任何选项的情况下发出 gzip 时,Kernel# 卡住而 Kernel#system 没有卡住

ruby - rb-libsvm 中的零概率

arrays - 在 Ruby 中将对象数组转换为 JSON

C# 从列表中选择随机元素

c# - 如何使用 HTML 敏捷包抓取内容

javascript - 使用 Newtonsoft、C# 反序列化 JSON 时出错

sql - rails postgresql。两个操作的碰撞