C#.NET与JAVA互通之AES加密解密V2024

net,java,aes,v2024 · 浏览次数 : 0

小编点评

本文主要讨论了C#和Java中的AES加密解密的使用方法及其注意点。文章首先概述了C#中AesUtil类中的加解密方法,包括CBC模式和ECB模式的加密解密。然后,对Java中的AesUtil类也进行了相应的介绍,并对比了两者的差异。 1. **C# AES 加密解密** - C# 中的AesUtil类提供了丰富的AES加密解密方法,包括CBC模式和ECB模式。 - 明文转换成byte数组时,双方需约定编码方式。 - 密文转成字符串时,也是双方协议好的编码方式。 - 对于不同的密钥长度(AES128, AES256),C# 有专门的实现方法。 2. **Java AES 加密解密** - Java 中的AesUtil类同样实现了AES加密解密,但略有不同。 - 与C#类似,密文转成字符串也是通过编码方式实现的。 - Java 使用PKCS5Padding填充方式,而C# 使用PKCS7Padding。 3. **AES KEY 变种** - 文章还提到了AES KEY可以有不同的变体,例如MD5哈希后的值,或者其他算法处理后的密钥。 - 在C#中,可以通过截取前16位作为AES128,或者进行MD5哈希后得到AES256。 总的来说,本文详细介绍了C#和Java中AES加密解密的处理流程和注意问题,为开发者在使用这两种语言时提供了一定的参考。

正文

C#.NET与JAVA互通之AES加密解密V2024

 

视频:

 

 

 

注意点:

1. KEY 和 IV 从字符串转byte数组时,双方要约定好编码,一般是UTF8。

2.明文从字符串转byte数组时,双方要约定好编码,一般是UTF8,也可以GB2312,但不能Encoding.Default。

3.加密后的结果,从byte数组转字符串时,双方要约定好编码,一般是Base64字符串。

4.NET 的PKCS7Padding 对应 JAVA 的:PKCS5Padding
5. AES128指的是密钥长度为16个字符串(16Byte * 8 = 128 bit),AES256指的是密钥长度为32个字符串(32Byte * 8 = 256 bit)。

6.AES KEY 的变种(MD5 HASH 后,正好是AES256,或截取前16位作为AES128)

 

一、C#.NET:

AesUtil:

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace CommonUtils
{
    /// <summary>
    /// AES 工具类,2024-06-07,runliuv。
    /// </summary>
    public static class AesUtil
    {

        /// <summary>
        /// AES CBC 解密
        /// </summary>
        /// <param name="decryptStr">要解密的串,base64字符串</param>
        /// <param name="aesKey">密钥</param>
        /// <param name="aesIV">IV</param>
        /// <returns></returns>
        public static string AesDecryptCBC(string decryptStr, string aesKey, string aesIV)
        {

            byte[] byteKEY = Encoding.UTF8.GetBytes(aesKey);
            byte[] byteIV = Encoding.UTF8.GetBytes(aesIV);

            byte[] byteDecrypt = Convert.FromBase64String(decryptStr);

            var _aes = new RijndaelManaged();
            _aes.Padding = PaddingMode.PKCS7;
            _aes.Mode = CipherMode.CBC;

            _aes.Key = byteKEY;
            _aes.IV = byteIV;

            var _crypto = _aes.CreateDecryptor();
            byte[] decrypted = _crypto.TransformFinalBlock(
                byteDecrypt, 0, byteDecrypt.Length);

            _crypto.Dispose();

            return Encoding.UTF8.GetString(decrypted);
        }

        /// <summary>
        /// AES CBC 解密,输入输出都是byte[],方便用各种编码转换成字符串
        /// </summary>
        /// <param name="byteDecrypt"></param>
        /// <param name="byteKEY"></param>
        /// <param name="byteIV"></param>
        /// <returns></returns>
        public static byte[] AesDecryptCBC(byte[] byteDecrypt, byte[] byteKEY, byte[] byteIV)
        {

            var _aes = new RijndaelManaged();
            _aes.Padding = PaddingMode.PKCS7;
            _aes.Mode = CipherMode.CBC;

            _aes.Key = byteKEY;
            _aes.IV = byteIV;

            var _crypto = _aes.CreateDecryptor();
            byte[] decrypted = _crypto.TransformFinalBlock(
                byteDecrypt, 0, byteDecrypt.Length);

            _crypto.Dispose();

            return decrypted;
        }

        /// <summary>
        /// AES CBC 加密,输出base64字符串。
        /// </summary>
        /// <param name="content"></param>
        /// <param name="aesKey"></param>
        /// <param name="aesIV"></param>
        /// <returns></returns>
        public static string AesEncryptCBC(string content, string aesKey, string aesIV)
        {

            byte[] byteKEY = Encoding.UTF8.GetBytes(aesKey);
            byte[] byteIV = Encoding.UTF8.GetBytes(aesIV);

            byte[] byteContnet = Encoding.UTF8.GetBytes(content);

            var _aes = new RijndaelManaged();
            _aes.Padding = PaddingMode.PKCS7;
            _aes.Mode = CipherMode.CBC;

            _aes.Key = byteKEY;
            _aes.IV = byteIV;

            var _crypto = _aes.CreateEncryptor();
            byte[] decrypted = _crypto.TransformFinalBlock(
                byteContnet, 0, byteContnet.Length);

            _crypto.Dispose();

            return Convert.ToBase64String(decrypted);
        }

        /// <summary>
        /// AES CBC 加密,输入输出都是byte[],方便用各种编码转换成字符串
        /// </summary>
        /// <param name="byteContnet"></param>
        /// <param name="byteKEY"></param>
        /// <param name="byteIV"></param>
        /// <returns></returns>
        public static byte[] AesEncryptCBC(byte[] byteContnet, byte[] byteKEY, byte[] byteIV)
        {

            var _aes = new RijndaelManaged();
            _aes.Padding = PaddingMode.PKCS7;
            _aes.Mode = CipherMode.CBC;

            _aes.Key = byteKEY;
            _aes.IV = byteIV;

            var _crypto = _aes.CreateEncryptor();
            byte[] decrypted = _crypto.TransformFinalBlock(
                byteContnet, 0, byteContnet.Length);

            _crypto.Dispose();

            return decrypted;
        }


        public static string AesEncryptECB(string content, string aesKey)
        {

            byte[] byteKEY = Encoding.UTF8.GetBytes(aesKey);

            byte[] byteContnet = Encoding.UTF8.GetBytes(content);

            var _aes = new RijndaelManaged();
            _aes.Padding = PaddingMode.PKCS7;
            _aes.Mode = CipherMode.ECB;

            _aes.Key = byteKEY;
            

            var _crypto = _aes.CreateEncryptor();
            byte[] decrypted = _crypto.TransformFinalBlock(
                byteContnet, 0, byteContnet.Length);

            _crypto.Dispose();

            return Convert.ToBase64String(decrypted);
        }

        public static string AesDecryptECB(string decryptStr, string aesKey)
        {

            byte[] byteKEY = Encoding.UTF8.GetBytes(aesKey);

            byte[] byteDecrypt = Convert.FromBase64String(decryptStr);

            var _aes = new RijndaelManaged();
            _aes.Padding = PaddingMode.PKCS7;
            _aes.Mode = CipherMode.ECB;

            _aes.Key = byteKEY;

            var _crypto = _aes.CreateDecryptor();
            byte[] decrypted = _crypto.TransformFinalBlock(
                byteDecrypt, 0, byteDecrypt.Length);

            _crypto.Dispose();

            return Encoding.UTF8.GetString(decrypted);
        }

    }
}

 

 

HashUtil

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace CommonUtils
{
    public static class HashUtil
    {

        public static string GetMd5(string src)
        {
            MD5 md =   MD5.Create();
            byte[] bytes = Encoding.UTF8.GetBytes(src);
            byte[] buffer2 = md.ComputeHash(bytes);
            string str = "";
            for (int i = 0; i < buffer2.Length; i++)
            {
                str = str + buffer2[i].ToString("x2");
            }
            return str;

        }

        public static IDictionary<string, string> ModelToDic<T1>(T1 cfgItem)
        {
            IDictionary<string, string> sdCfgItem = new Dictionary<string, string>();

            System.Reflection.PropertyInfo[] cfgItemProperties = cfgItem.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            foreach (System.Reflection.PropertyInfo item in cfgItemProperties)
            {
                string name = item.Name;
                object value = item.GetValue(cfgItem, null);
                if (value != null && (item.PropertyType.IsValueType || item.PropertyType.Name.StartsWith("String")) && !string.IsNullOrWhiteSpace(value.ToString()))
                {
                    sdCfgItem.Add(name, value.ToString());
                }
            }

            return sdCfgItem;
        }

        public static IDictionary<string, string> AsciiDictionary(IDictionary<string, string> sArray)
        {
            IDictionary<string, string> asciiDic = new Dictionary<string, string>();
            string[] arrKeys = sArray.Keys.ToArray();
            Array.Sort(arrKeys, string.CompareOrdinal);
            foreach (var key in arrKeys)
            {
                string value = sArray[key];
                asciiDic.Add(key, value);
            }
            return asciiDic;
        }

        public static string BuildQueryString(IDictionary<string, string> sArray)
        {

            //拼接 K=V&A=B&c=1 这种URL

            StringBuilder sc = new StringBuilder();

            foreach (var item in sArray)
            {
                string name = item.Key;
                string value = item.Value;
                if (!string.IsNullOrWhiteSpace(value))
                {
                    sc.AppendFormat("{0}={1}&", name, value);
                }

            }

            string fnlStr = sc.ToString();
            fnlStr = fnlStr.TrimEnd('&');

            return fnlStr;
        }

    }
}

 

 

 

.NET 使用:

 

using CommonUtils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //.NET 的PKCS7 对应 JAVA 的:PKCS5Padding
                TestAesCbc();

                TestAesECB();

                //JAVA加密,.NET 解密
                string javaStr = "FfRdTUVCFSknpYNXoMHQOAQNEqkHY1uU19u/3wWH6Js=";
                Console.WriteLine("JAVA加密后的字符串:" + javaStr);
                string aesKey = "1234567890123456";//AES KEY 与 JAVA 保持一致
                string decryptedStr = AesUtil.AesDecryptECB(javaStr, aesKey);
                Console.WriteLine("自加,自解:" + decryptedStr);


                //有的AES加密,不是直接把字符串当KEY使用,而是把原密钥 MD5 HASH后,作为AES 的KEY。
                TestAesKeyTrap();
            }
            catch (Exception ex)
            {
                Console.WriteLine("ex!" + ex.Message);
            }
            Console.WriteLine("结束!");
            Console.ReadKey();
        }

        static void TestAesCbc()
        {
            Console.WriteLine("-- TestAesCbc --" );
            string aesKey = "1234567890123456";//16位或32位
            string aesIV = "abcdefghABCDEFGH";

            string aa = "这边是 .net aes 加密";
            Console.WriteLine("待加密字符串:" + aa);
            string encryptedStr = AesUtil.AesEncryptCBC(aa, aesKey, aesIV);
            Console.WriteLine("加密字符串:" + encryptedStr);
            //自加,自解
            string decryptedStr = AesUtil.AesDecryptCBC(encryptedStr, aesKey, aesIV);
            Console.WriteLine("自加,自解:" + decryptedStr);
        }

        static void TestAesECB()
        {
            Console.WriteLine("-- TestAesECB --");

            string aesKey = "1234567890123456";//16位或32位

            string aa = ".net aes 加密";
            Console.WriteLine("待加密字符串:" + aa);
            string encryptedStr = AesUtil.AesEncryptECB(aa, aesKey);
            Console.WriteLine("加密字符串:" + encryptedStr);
            //自加,自解
            string decryptedStr = AesUtil.AesDecryptECB(encryptedStr, aesKey);
            Console.WriteLine("自加,自解:" + decryptedStr);
        }

        /// <summary>
        /// AES KEY 的变种(MD5 HASH 后,正好是AES256,或截取前16位作为AES128)
        /// </summary>
        static void TestAesKeyTrap()
        {
            Console.WriteLine("-- TestAesECB --");

            string orgKey = "HelloWorld";//不够16位或32位
            //string aesKey = "HelloWorld";//不够16位或32位

            string aesKey = HashUtil.GetMd5(orgKey).ToLower().Substring(16);
            Console.WriteLine("GetMd5后的长度:" + aesKey.Length.ToString());

            string aa = ".net aes 加密";
            Console.WriteLine("待加密字符串:" + aa);
            string encryptedStr = AesUtil.AesEncryptECB(aa, aesKey);
            Console.WriteLine("加密字符串:" + encryptedStr);
            //自加,自解
            string decryptedStr = AesUtil.AesDecryptECB(encryptedStr, aesKey);
            Console.WriteLine("自加,自解:" + decryptedStr);
        }
    }
}

 

 

 

二、JAVA:

AesUtil:

 

 

package org.runliuv;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class AesUtil {

    private static final String charset = "UTF-8";

    /**
     * 加密
     * @param content
     * @param key
     * @param iv
     * @return
     * @throws Exception
     */
    public static String AesEncryptCBC(String content, String key, String iv)
            throws Exception {

        //明文
        byte[] contentBytes = content.getBytes(charset);

        //AES KEY
        byte[] keyBytes = key.getBytes(charset);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

        //AES IV
        byte[] initParam = iv.getBytes(charset);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
        byte[] byEnd = cipher.doFinal(contentBytes);

        //加密后的byte数组转BASE64字符串
        String strEnd = Base64.getEncoder().encodeToString(byEnd);
        return strEnd;
    }

    /**
     * 解密
     * @param content
     * @param key
     * @param iv
     * @return
     * @throws Exception
     */
    public static String AesDecryptCBC(String content, String key, String iv)
            throws Exception {
        //反向解析BASE64字符串为byte数组
        byte[] encryptedBytes = Base64.getDecoder().decode(content);

        //AES KEY
        byte[] keyBytes = key.getBytes(charset);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

        //AES IV
        byte[] initParam = iv.getBytes(charset);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
        byte[] byEnd = cipher.doFinal(encryptedBytes);

        //加密后的byte数组直接转字符串
        String strEnd = new String(byEnd, charset);
        return strEnd;
    }

    public static String AesEncryptECB(String content, String key)
            throws Exception {

        //明文
        byte[] contentBytes = content.getBytes(charset);

        //AES KEY
        byte[] keyBytes = key.getBytes(charset);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] byEnd = cipher.doFinal(contentBytes);

        //加密后的byte数组转BASE64字符串
        String strEnd = Base64.getEncoder().encodeToString(byEnd);
        return strEnd;
    }

    public static String AesDecryptECB(String content, String key)
            throws Exception {
        //反向解析BASE64字符串为byte数组
        byte[] encryptedBytes = Base64.getDecoder().decode(content);

        //AES KEY
        byte[] keyBytes = key.getBytes(charset);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] byEnd = cipher.doFinal(encryptedBytes);

        //加密后的byte数组直接转字符串
        String strEnd = new String(byEnd, charset);
        return strEnd;
    }

}

 

 

java使用:

 

package org.runliuv;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {

        try
        {
            TestAesCbc();

            TestAesECB();

            //.net aes cbc 加,JAVA 解密
            String netStr="Mrs6Ufo2Y4ulWiksFSWFnUNKVSO5COruAlgQ5ws7FL0=";
            System.out.println("-- .net 加密后的内容:" + netStr);
            String aesKey = "1234567890123456";//与.net 保持一致
            String aesIV = "abcdefghABCDEFGH";//与.net 保持一致

            String decryptedStr = AesUtil.AesDecryptCBC(netStr, aesKey, aesIV);
            System.out.println(".net aes cbc 加,JAVA 解密:" + decryptedStr);

        }catch (Exception ex){

            System.out.println( "ex!"+ex.getMessage() );
        }
        System.out.println( "结束!" );
    }

    static void  TestAesCbc(){

        try {
            System.out.println("-- TestAesCbc --" );

            //16位 (32位,jdk8 老版本,需要放JAR包才支持32位的)
            String aesKey = "1234567890123456";
            String aesIV = "abcdefghABCDEFGH";

            String aa = "java aes 加密,2024-06-07。";
            System.out.println("待加密字符串:" + aa);
            String encryptedStr = AesUtil.AesEncryptCBC(aa, aesKey, aesIV);
            System.out.println("加密字符串:" + encryptedStr);
            //自加,自解
            String decryptedStr = AesUtil.AesDecryptCBC(encryptedStr, aesKey, aesIV);
            System.out.println("自加,自解:" + decryptedStr);

        }catch (Exception ex){

            System.out.println( "ex!"+ex.getMessage() );
        }

    }

    static void  TestAesECB(){

        try {
            System.out.println("-- TestAesECB --" );

            //16位 (32位,jdk8 老版本,需要放JAR包才支持32位的)
            String aesKey = "1234567890123456";

            String aa = "java aes 加密,2024-06-07。";
            System.out.println("待加密字符串:" + aa);
            String encryptedStr = AesUtil.AesEncryptECB(aa, aesKey);
            System.out.println("加密字符串:" + encryptedStr);
            //自加,自解
            String decryptedStr = AesUtil.AesDecryptECB(encryptedStr, aesKey);
            System.out.println("自加,自解:" + decryptedStr);

        }catch (Exception ex){

            System.out.println( "ex!"+ex.getMessage() );
        }

    }
}

 

 

 

-

与C#.NET与JAVA互通之AES加密解密V2024相似的内容:

C#.NET与JAVA互通之AES加密解密V2024

C#.NET与JAVA互通之AES加密解密V2024 视频: 注意点: 1. KEY 和 IV 从字符串转byte数组时,双方要约定好编码,一般是UTF8。 2.明文从字符串转byte数组时,双方要约定好编码,一般是UTF8,也可以GB2312,但不能Encoding.Default。 3.加密后的

C#.NET与JAVA互通之DES加密V2024

C#.NET与JAVA互通之DES加密V2024 配置视频: 环境: .NET Framework 4.6 控制台程序 JAVA这边:JDK8 (1.8) 控制台程序 注意点: 1.由于密钥、明文、密文的输入输出参数,都是byte数组(byte[]),所以:字符串转byte数组(byte[])环节,

C#.NET与JAVA互通之MD5哈希V2024

C#.NET与JAVA互通之MD5哈希V2024 配套视频: 要点: 1.计算MD5时,SDK自带的计算哈希(ComputeHash)方法,输入输出参数都是byte数组。就涉及到字符串转byte数组转换时,编码选择的问题。 2.输入参数,字符串转byte数组时,编码双方要统一,一般为:UTF-8。

.NET科普:.NET简史、.NET Standard以及C#和.NET Framework之间的关系

最近在不少自媒体上看到有关.NET与C#的资讯与评价,感觉大家对.NET与C#还是不太了解,尤其是对2016年6月发布的跨平台.NET Core 1.0,更是知之甚少。在考虑一番之后,还是决定写点东西总结一下,也回顾一下.NET的发展历史。 首先,你没看错,.NET是跨平台的,可以在Windows、

C#.Net筑基-基础知识

C# (读作C Sharp)是由微软公司开发的一种面向对象、类型安全、高效且简单的编程语言,最初于 2000 年发布,并随后成为 .NET 框架的一部分。所以学习C#语言的同时,也是需要同步学习.NET框架的,不过要要注意C#与.NET的对应版本。

Unity框架与.NET, Mono框架的关系

什么是C# C#是一种面向对象的编程语言。 什么是.NET .NET是一个开发框架,它遵循并采用CIL(Common Intermediate Language)和CLR(Common Language Runtime)两种约定, CIL标准为一种编译标准:将不同编程语言(C#, JS, VB等)使

像go 一样 打造.NET 单文件应用程序的编译器项目bflat 发布 7.0版本

现代.NET和C#在低级/系统程序以及与C/C++/Rust等互操作方面的能力完全令各位刮目相看了,有人用C#开发的64位操作系统: GitHub - nifanfa/MOOS: C# x64 operating system pro...,截图要介绍的是一个结合Roslyn和NativeAOT的实

.NET周报 【5月第4期 2023-05-27】

## 国内文章 ### C#使用词嵌入向量与向量数据库为大语言模型(LLM)赋能长期记忆实现私域问答机器人落地之openai接口平替 https://www.cnblogs.com/gmmy/p/17430613.html 在上一篇[文章](https://www.cnblogs.com/gmmy/

[转帖]别催了,别催了,这篇文章我一次性把 Shell 的内容说完

https://my.oschina.net/jiagoushi/blog/6037198 Shell 搜索与匹配 1、在文件中查找字符串 grep 命令可以搜索文件,查找指定的字符串。 $ grep myvar *.c 在这个例子中,我们搜索的文件全都位于当前目录下。因此,我们只使用了简单的 sh

如何洞察 .NET程序 非托管句柄泄露

## 一:背景 ### 1. 讲故事 很多朋友可能会有疑问,C# 是一门托管语言,怎么可能会有非托管句柄泄露呢? 其实一旦 C# 程序与 C++ 语言交互之后,往往就会被后者拖入非托管泥潭,让我们这些调试者被迫探究 `非托管领域问题`。 ## 二:非托管句柄泄露 ### 1. 测试案例 为了方便讲述