当前位置: 首页 > 知识库问答 >
问题:

AES GCM加密使用C#vs PHP

郑光济
2023-03-14

我正在使用C#在客户机/服务器应用程序中执行一些加密方法。NET框架和PHP。加密方法是AES-256-GCM,在PHP中非常简单。这个NET代码,我从这里复制了一些修改。这个NET版本产生了不同的值。

在PHP版本中,我可以这样写

<?php
   
$dynamicSecretKey = "2192B39425BBD08B6E8E61C5D1F1BC9F428FC569FBC6F78C0BC48FCCDB0F42AE";
$iv = "E1E592E87225847C11D948684F3B070D";
$plainText = 'Test only. PHP and C# encryption';
$tag = null;

$content = openssl_encrypt($plainText, 'AES-256-GCM', $dynamicSecretKey, OPENSSL_RAW_DATA,$iv, $tag);

echo bin2hex($tag)."\n";

$cipherText = base64_encode($content.$tag);

echo $cipherText."\n";

$cipherTextWithTag = base64_decode($cipherText);
echo bin2hex($cipherTextWithTag);
echo "\n";

$tag = substr($cipherTextWithTag , -16, 16);
$cipherText = substr($cipherTextWithTag, 0, - 16);

$decryptedText = openssl_decrypt($cipherText, 'AES-256-GCM', $dynamicSecretKey, OPENSSL_RAW_DATA, $iv,$tag);

echo $decryptedText;

?>

在C#中,我试图使其保持一致

private RunTest()
{
    //$dynamicSecretKey = "2192B39425BBD08B6E8E61C5D1F1BC9F428FC569FBC6F78C0BC48FCCDB0F42AE";
    string dynamicSecretKey = "3777217A25432A462D4A614E645267556B58703272357538782F413F4428472B";
    //$iv = "E1E592E87225847C11D948684F3B070D";
    string iv = "E1E592E87225847C11D94868";
    //$plainText = 'Test only. PHP and C# encryption';
    string plainText = "Test only. PHP and C# encryption";
    //$tag = null;
    byte[] tag = null;

    //$content = openssl_encrypt($plainText, 'AES-256-GCM', $dynamicSecretKey, OPENSSL_RAW_DATA,$iv, $tag);
    var content = AesGcm.Openssl_Encrypt(plainText, dynamicSecretKey, iv);
    //$cipherText = base64_encode($content.$tag);
    string cipherText = AesGcm.Base64Encode(AesGcm.Combine(content.cipherText, content.tag));
    //bool same = cipherText.Equals("+u3YJpiHMy6p0mDxlquYq7utAOk7r6ppKGcnYAVD9iMPSe7fhWNNoMNto6Z6p0tM");

    //$cipherTextWithTag = base64_decode($cipherText);
    string cipherTextWithTag = AesGcm.Base64Decode(cipherText); //RESULTED UNREAD CHARACTERS

    //$tag = substr($cipherTextWithTag, -16, 16);
    //tag = cipherTextWithTag.Substring(cipherTextWithTag.Length - 16, 16);
    //$cipherText = substr($cipherTextWithTag, 0, -16);
    //cipherText = cipherTextWithTag.Substring(0, cipherTextWithTag.Length - 16);
    string decryptedText = AesGcm.Openssl_Decrypt(cipherText, dynamicSecretKey, iv, AesGcm.ByteArrayToHex(content.tag)); //ERROR
}

internal static class AesGcm
{
    internal static (byte[] ciphertext, byte[] nonce, byte[] tag) Encrypt(string plaintext, byte[] key, byte[] iv)
    {
        const int nonceLength = 12; // in bytes
        const int tagLenth = 16; // in bytes

        var plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
        var bcCiphertext = new byte[plaintextBytes.Length + tagLenth];

        var cipher = new GcmBlockCipher(new AesEngine());
        var parameters = new AeadParameters(new KeyParameter(key), tagLenth * 8, iv);
        cipher.Init(true, parameters);

        var offset = cipher.ProcessBytes(plaintextBytes, 0, plaintextBytes.Length, bcCiphertext, 0);
        cipher.DoFinal(bcCiphertext, offset);

        // Bouncy Castle includes the authentication tag in the ciphertext
        var ciphertext = new byte[plaintextBytes.Length];
        var tag = new byte[tagLenth];
        Buffer.BlockCopy(bcCiphertext, 0, ciphertext, 0, plaintextBytes.Length);
        Buffer.BlockCopy(bcCiphertext, plaintextBytes.Length, tag, 0, tagLenth);

        return (ciphertext, iv, tag);
    }

    private static string Decrypt(byte[] ciphertext, byte[] key, byte[] iv, byte[] tag)
    {
        var plaintextBytes = new byte[ciphertext.Length];

        var cipher = new GcmBlockCipher(new AesEngine());
        var parameters = new AeadParameters(new KeyParameter(key), tag.Length * 8, iv);
        cipher.Init(false, parameters);

        var bcCiphertext = ciphertext.Concat(tag).ToArray();

        var offset = cipher.ProcessBytes(bcCiphertext, 0, bcCiphertext.Length, plaintextBytes, 0);
        cipher.DoFinal(plaintextBytes, offset);

        return Encoding.UTF8.GetString(plaintextBytes);
    }

    internal static (byte[] cipherText, byte[] tag) Openssl_Encrypt(string plaintext, string key, string iv)
    {
        var plainTextBytes = Encoding.UTF8.GetBytes(plaintext);
        var bKey = HexToByteArray(key);
        var bIv = HexToByteArray(iv);
        var result = Encrypt(plaintext, bKey, bIv);
        return (result.ciphertext, result.tag);
    }

    internal static string Openssl_Decrypt(string ciphertext, string key, string iv, string tag)
    {
        var bKey = HexToByteArray(key);
        var bIv = HexToByteArray(iv);
        var bTag = HexToByteArray(tag);
        var bCipherText = Convert.FromBase64String(ciphertext);

        var result = Decrypt(bCipherText, bKey, bIv, bTag);
        return Base64Decode(result);
    }

    public static byte[] HexToByteArray(string hex)
    {
        return Enumerable.Range(0, hex.Length)
                         .Where(x => x % 2 == 0)
                         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                         .ToArray();
    }

    public static string ByteArrayToHex(byte[] ba) => BitConverter.ToString(ba).Replace("-", "").ToLower();

    public static string Base64Encode(string plainText)
    {
        var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(plainTextBytes);
    }

    public static string Base64Decode(string base64EncodedData)
    {
        var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
        return Encoding.UTF8.GetString(base64EncodedBytes);
    }

    public static string Base64Encode(byte[] plainText)
    {
        return Convert.ToBase64String(plainText);
    }

    public static string Base64Decode(byte[] base64EncodedData)
    {
        return Encoding.UTF8.GetString(base64EncodedData);
    }

    public static byte[] Combine(params byte[][] arrays)
    {
        byte[] rv = new byte[arrays.Sum(a => a.Length)];
        int offset = 0;
        foreach (byte[] array in arrays)
        {
            System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
            offset += array.Length;
        }
        return rv;
    }
}

编辑:

所有方法都包括在内。

这个问题不是重复的

共有1个答案

袁青青
2023-03-14

你做的第一件奇怪的事情是在加密结束时:

// BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count)
Buffer.BlockCopy(bcCiphertext, 0, ciphertext, 0, plaintextBytes.Length);
Buffer.BlockCopy(bcCiphertext, plaintextBytes.Length, tag, 0, tagLenth);

您正在将字节复制到密文和标记(本地数组)!?

另一个奇怪的事情:

// new AeadParameters(KeyParameter key, int macSize, byte[] nonce)
var parameters = new AeadParameters(new KeyParameter(key), tagLenth * 8, iv);

你在把IV扇区写入当前字段?!

 类似资料:
  • 问题内容: 我已经获得了用于加密的Java实现,但是很遗憾,我们是.net商店,并且无法将Java集成到我们的解决方案中。不幸的是,我也不是Java专家,所以我已经为此奋斗了几天,以为我最终会在这里寻求帮助。 我一直在寻找一种与Java加密工作方式相匹配的方法,并且已经找到了在c#中使用RijndaelManaged所需的分辨率。我真的很近。我在c#中返回的字符串与前半部分匹配,但后半部分不同。

  • 问题内容: 我似乎找不到使用AES 128位加密的漂亮示例。 有人有示例代码吗? 问题答案: 如果您只想使用内置的加密提供程序RijndaelManaged,请查看以下帮助文章(它也有一个简单的代码示例): http://msdn.microsoft.com/zh-CN/library/system.security.cryptography.rijndaelmanaged.aspx 以防万一您急

  • 本文向大家介绍C#使用 Salt + Hash 来为密码加密,包括了C#使用 Salt + Hash 来为密码加密的使用技巧和注意事项,需要的朋友参考一下 (一) 为什么要用哈希函数来加密密码 如果你需要保存密码(比如网站用户的密码),你要考虑如何保护这些密码数据,象下面那样直接将密码写入数据库中是极不安全的,因为任何可以打开数据库的人,都将可以直接看到这些密码。 解决的办法是将密码加密后再存储进

  • 我正在使用Objective c(iPad端)和c#(.NET,服务器站点)之间的加密/解密。我使用的是以下链接中的代码:iPhone/C#AES加密 我们在服务器端加密一个XML并使用web服务将其发送到iPad端。在iPad端,当我尝试解密时,它正在创建解密数据,但无法将该数据转换为字符串。使用NSUTF8StringEncoding将数据转换为字符串时会遇到一些问题。 谢谢你!

  • 我是密码学的新手。我的要求是对使用openssl加密/解密的文本进行解密/加密。我们在Openssl中使用的算法是aes-256-cbc。因此,我尝试在我的应用程序中实现相同的功能。到目前为止,在谷歌搜索了很多次之后,我所能做的就是。。 我的openssl命令是 我的密钥长度是32位IV是16位 Thnx...

  • 我正在尝试使用CryptoJS在JavaScript中进行加密,在C#中进行解密。花了很多时间试图让两种技术返回相同的输出。但是,输出是不同的--CryptoJS产生的加密字符串不同于C#产生的加密字符串。我做错了什么?谢谢你的帮助。