본문 바로가기
개발언어/Java

AES256 java & c# encrypt, decrypt 처리

by 공장장코난 2021. 12. 6.

C#에서 생성한 AES256 암호화 값을 java에서 복호화하여 처리해야 하는데, 아래 3가지 내용중 하나라도 다를 경우 복호화 정상으로 되지 않는다. 이참에 서로 다른 language간 AES256 암/복호화 방법을 정리해 둔다.

주요 점검 포인트
1.암호화 키 (나의 경우엔 32byte 키를 사용한다.)
2.IV initialvector (16byte를 사용함)
3.CipherMode (CBC, ECB, OFB, CFB, CTS 등이 있으나 CBC로 함)
4.PaddingMode (C#의 경우엔 PKCS7, JAVA는 PKCS5)

암/복호화 과정은 아래와 같은 순서대로 진행되는데, 아래 블로그에 잘 정리되어 있다.

  • 암호화
    plain text > plain bytes > encrypt > encrypted bytes > encrypted base64 text
  • 복호화
    encrpyted base64 text > encrypted bytes > decrypt > plain bytes > plain text

https://velog.io/@bang9dev/AES-256-%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC

 

AES-256 에 관하여

협력사에서 AES256 방식으로 암호화 된 데이터를 제공해주기로 했다.내가 받은것은 암호화 키 달랑 하나뿐...거기에 협력사에서 키를 잘못 처리해서 사용해서 전달받은 값은 복호화가 되지 않는

velog.io

한가지 추가하자면 http로 전송하므로 string -> hex string으로 변환하여 전송 한다. 

Java 코드

package com.codepulse.AES256Chiper.Common;

import org.apache.tomcat.util.codec.binary.Base64;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

public class AES256Chiper {

    private static volatile  AES256Chiper Instance;

    public static byte[] IV = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };

    public static AES256Chiper getInstance() {
        if (Instance == null) {
            synchronized (AES256Chiper.class) {
                if (Instance == null) Instance = new AES256Chiper();
            }
        }
        return Instance;
    }

    private AES256Chiper() {

    }

    //Encrypt plainText
    public static String encrypt(String encKey, String plainText) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {

        byte[] keyData = encKey.getBytes("UTF-8");

        SecretKey secretKey = new SecretKeySpec(keyData, "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(IV));

        byte[] encData  = cipher.doFinal(plainText.getBytes("UTF-8"));

        return ConvertStringToHex(new String(Base64.encodeBase64(encData)));
    }

    //Decrypt encText
    public static String decrypt(String encKey, String encText) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {

        byte[] keyData = encKey.getBytes("UTF-8");

        SecretKey secretKey = new SecretKeySpec(keyData, "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(IV));

        //byte[] decData = Base64.decodeBase64(encText.getBytes());
        byte[] decData = Base64.decodeBase64(ConvertHexToString(encText).getBytes());

        return new String(cipher.doFinal(decData), "UTF-8");
    }

    public static String ConvertStringToHex(String str) {
        // display in lowercase, default
        char[] chars = Hex.encodeHex(str.getBytes(StandardCharsets.UTF_8));

        return String.valueOf(chars);
    }

    // Hex -> Decimal -> Char
    public static String ConvertHexToString(String hex) {

        StringBuilder result = new StringBuilder();

        // split into two chars per loop, hex, 0A, 0B, 0C...
        for (int i = 0; i < hex.length() - 1; i += 2) {

            String tempInHex = hex.substring(i, (i + 2));

            //convert hex to decimal
            int decimal = Integer.parseInt(tempInHex, 16);

            // convert the decimal to char
            result.append((char) decimal);
        }

        return result.toString();
    }
}

 

C# 코드

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace VisitlogAdminApp.Common
{
    /// <summary>
    /// AES256 암호화 Class
    /// </summary>
    public class AES256Chiper
    {
        public static string Encrypt(string plainText, string encKey)
        {
            string output = string.Empty;

            try
            {
                RijndaelManaged aes = new RijndaelManaged();
                aes.KeySize = 256;
                aes.BlockSize = 128;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                aes.Key = Encoding.UTF8.GetBytes(encKey);
                aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

                var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
                byte[] xBuff = null;
                using (var ms = new MemoryStream())
                {
                    using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
                    {
                        byte[] xXml = Encoding.UTF8.GetBytes(plainText);
                        cs.Write(xXml, 0, xXml.Length);
                    }

                    xBuff = ms.ToArray();
                }

                output = ConvertStringToHex(Convert.ToBase64String(xBuff));

                xBuff = null;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception:{0}", ex.Message.ToString());
            }

            return output;
        }

        /// <summary>
        /// AES256 복호화
        /// </summary>
        /// <returns></returns>
        public static string Decrypt(string encText, string encKey)
        {
            string output = string.Empty;

            try
            {
                RijndaelManaged aes = new RijndaelManaged();
                aes.KeySize = 256;
                aes.BlockSize = 128;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;
                aes.Key = Encoding.UTF8.GetBytes(encKey);
                aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

                var decrypt = aes.CreateDecryptor();
                byte[] xBuff = null;
                using (var ms = new MemoryStream())
                {
                    using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
                    {
                        byte[] xXml = Convert.FromBase64String(ConvertHexToString(encText));
                        cs.Write(xXml, 0, xXml.Length);
                    }

                    xBuff = ms.ToArray();
                }

                output = Encoding.UTF8.GetString(xBuff);

                xBuff = null;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception:{0}", ex.Message.ToString());
            }
            
            return output;
        }

        #region HexString
        public static string ConvertStringToHex(string asciiString)
        {
            string hex = "";
            foreach (char c in asciiString)
            {
                int tmp = c;
                hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
            }
            return hex;
        }

        public static string ConvertHexToString(string HexValue)
        {
            string StrValue = "";
            while (HexValue.Length > 0)
            {
                StrValue += System.Convert.ToChar(System.Convert.ToUInt32(HexValue.Substring(0, 2), 16)).ToString();
                HexValue = HexValue.Substring(2, HexValue.Length - 2);
            }
            return StrValue;
        }
        #endregion
    }
}

java에서 암호화 한 데이터를 C#에서 복호화 하는데 성공했다.  다시 서비스를 만들기 시작..

참조
https://bigenergy.tistory.com/entry/AES256-%EC%95%94%ED%98%B8%ED%99%94-%EB%B3%B5%ED%98%B8%ED%99%94-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD-%EB%B0%8F-%EC%83%98%ED%94%8C-%EC%BD%94%EB%93%9C

 

AES256 암호화, 복호화 주의사항 및 샘플 코드

VB6으로 AES256 암호화를 하다가 보니 다른 언어로 개발된 프로그램과 통신할때 이런 저런 문제가 많이 나오네요. 그래서 발생했던 문제점 관련하여 내용을 정리해 보았습니다. AES256 암호화시 중

bigenergy.tistory.com