AES256 암복호화 - JAVA & C#

C# Language 에서 AES256으로 encrypt 되어 있는 데이터를 Java Language 에서 복호화해서 처리해야 하는 경우가 생겼다.

서로 다른 Language 에서 암호화 키, IV initialvector, CipherMMode, PaddingMode 등 하나라도 어긋날 경우 암호화 값은 달라지게 된다.


AES 암호화 복호화에 필요한 네가지는 아래와 같다.

1. Secret Key

2. IV (Initialize Vector)

3. Chpher Mode

4. Padding Mode


보통 Base64 기반이니까, URL로 전달할거면 encodeURIComponent 로 인코딩할건지 Base64 URL Safe 핸들링(base64 문자열의 + 와 / 를 - 와 _ 로 치환) 할건지 정해야 한다.


JAVA 소스


  1. package com.skhynix;
  2. import java.nio.charset.StandardCharsets;
  3. import java.security.InvalidAlgorithmParameterException;
  4. import java.security.InvalidKeyException;
  5. import java.security.NoSuchAlgorithmException;
  6. import javax.crypto.BadPaddingException;
  7. import javax.crypto.Cipher;
  8. import javax.crypto.IllegalBlockSizeException;
  9. import javax.crypto.NoSuchPaddingException;
  10. import javax.crypto.SecretKey;
  11. import javax.crypto.spec.IvParameterSpec;
  12. import javax.crypto.spec.SecretKeySpec;
  13. import org.apache.commons.codec.binary.Hex;
  14. import org.apache.tomcat.util.codec.binary.Base64;
  15. public class AES256Chiper {
  16. private static volatile AES256Chiper Instance;
  17. public static byte[] IV = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
  18. public static AES256Chiper getInstance() {
  19. if (Instance == null) {
  20. synchronized (AES256Chiper.class) {
  21. if (Instance == null) Instance = new AES256Chiper();
  22. }
  23. }
  24. return Instance;
  25. }
  26. private AES256Chiper() {
  27. }
  28. //Encrypt plainText
  29. public static String encrypt(String encKey, String plainText) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
  30. byte[] keyData = encKey.getBytes("UTF-8");
  31. SecretKey secretKey = new SecretKeySpec(keyData, "AES");
  32. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  33. cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(IV));
  34. byte[] encData = cipher.doFinal(plainText.getBytes("UTF-8"));
  35. return ConvertStringToHex(new String(Base64.encodeBase64(encData)));
  36. }
  37. //Decrypt encText
  38. public static String decrypt(String encKey, String encText) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
  39. byte[] keyData = encKey.getBytes("UTF-8");
  40. SecretKey secretKey = new SecretKeySpec(keyData, "AES");
  41. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  42. cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(IV));
  43. //byte[] decData = Base64.decodeBase64(encText.getBytes());
  44. byte[] decData = Base64.decodeBase64(ConvertHexToString(encText).getBytes());
  45. return new String(cipher.doFinal(decData), "UTF-8");
  46. }
  47. public static String ConvertStringToHex(String str) {
  48. // display in lowercase, default
  49. char[] chars = Hex.encodeHex(str.getBytes(StandardCharsets.UTF_8));
  50. return String.valueOf(chars);
  51. }
  52. // Hex -> Decimal -> Char
  53. public static String ConvertHexToString(String hex) {
  54. StringBuilder result = new StringBuilder();
  55. // split into two chars per loop, hex, 0A, 0B, 0C...
  56. for (int i = 0; i < hex.length() - 1; i += 2) {
  57. String tempInHex = hex.substring(i, (i + 2));
  58. //convert hex to decimal
  59. int decimal = Integer.parseInt(tempInHex, 16);
  60. // convert the decimal to char
  61. result.append((char) decimal);
  62. }
  63. return result.toString();
  64. }
  65. }



C# 소스

  1.     /// <summary>
  2. /// AES256 암호화 Class
  3. /// </summary>
  4. public class AES256Chiper
  5. {
  6. public static string Encrypt(string plainText, string encKey)
  7. {
  8. string output = string.Empty;
  9. try
  10. {
  11. RijndaelManaged aes = new RijndaelManaged();
  12. aes.KeySize = 256;
  13. aes.BlockSize = 128;
  14. aes.Mode = CipherMode.CBC;
  15. aes.Padding = PaddingMode.PKCS7;
  16. aes.Key = Encoding.UTF8.GetBytes(encKey);
  17. aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  18. var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
  19. byte[] xBuff = null;
  20. using (var ms = new MemoryStream())
  21. {
  22. using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
  23. {
  24. byte[] xXml = Encoding.UTF8.GetBytes(plainText);
  25. cs.Write(xXml, 0, xXml.Length);
  26. }
  27. xBuff = ms.ToArray();
  28. }
  29. output = ConvertStringToHex(Convert.ToBase64String(xBuff));
  30. xBuff = null;
  31. }
  32. catch (Exception ex)
  33. {
  34. Debug.WriteLine("Exception:{0}", ex.Message.ToString());
  35. }
  36. return output;
  37. }
  38. /// <summary>
  39. /// AES256 복호화
  40. /// </summary>
  41. /// <returns></returns>
  42. public static string Decrypt(string encText, string encKey)
  43. {
  44. string output = string.Empty;
  45. try
  46. {
  47. RijndaelManaged aes = new RijndaelManaged();
  48. aes.KeySize = 256;
  49. aes.BlockSize = 128;
  50. aes.Mode = CipherMode.CBC;
  51. aes.Padding = PaddingMode.PKCS7;
  52. aes.Key = Encoding.UTF8.GetBytes(encKey);
  53. aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  54. var decrypt = aes.CreateDecryptor();
  55. byte[] xBuff = null;
  56. using (var ms = new MemoryStream())
  57. {
  58. using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
  59. {
  60. byte[] xXml = Convert.FromBase64String(ConvertHexToString(encText));
  61. cs.Write(xXml, 0, xXml.Length);
  62. }
  63. xBuff = ms.ToArray();
  64. }
  65. output = Encoding.UTF8.GetString(xBuff);
  66. xBuff = null;
  67. }
  68. catch (Exception ex)
  69. {
  70. Debug.WriteLine("Exception:{0}", ex.Message.ToString());
  71. }
  72. return output;
  73. }
  74. #region HexString
  75. public static string ConvertStringToHex(string asciiString)
  76. {
  77. string hex = "";
  78. foreach (char c in asciiString)
  79. {
  80. int tmp = c;
  81. hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
  82. }
  83. return hex;
  84. }
  85. public static string ConvertHexToString(string HexValue)
  86. {
  87. string StrValue = "";
  88. while (HexValue.Length > 0)
  89. {
  90. StrValue += System.Convert.ToChar(System.Convert.ToUInt32(HexValue.Substring(0, 2), 16)).ToString();
  91. HexValue = HexValue.Substring(2, HexValue.Length - 2);
  92. }
  93. return StrValue;
  94. }
  95. #endregion
  96. }
* 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음
작성자 소개
초이 프로필
WrapUp 블로거

초이

반려견을 좋아하고, 차를 좋아하고, 여행을 좋아하고, 맛집을 찾아 즐기는 웹 개발자 입니다^^