JAVA에서 개인키와 공개키를 발급하고 C# 에서 공개키를 이용해 암호화 / JAVA에서 복호화 하는 과정을 소개 합니다.
C# 코드
using System;
using System.Net;
using System.Text;
using System.IO;
using System.Web.Script.Serialization;
using System.Security.Cryptography;
public partial class NcoreEPWorkReport : System.Web.UI.Page
{
private String ResponseString = string.Empty;
private Dictionary<String, String> ResponseJson = null;
protected void Page_Load(object sender, EventArgs e)
{
ResponseJson = new Dictionary<string, string>();
String service = "http://localhost:8000//rest/login/rasKeyData.json";
this.GetGet(service, null, null);
Dictionary<String, Object> _postData = new Dictionary<string, object>();
string publicKeyText = string.Empty;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
RSAParameters publicKey = new RSAParameters();
publicKey.Modulus = Convert.FromBase64String(this.ResponseJson["modulusString"]); //JAVA에서 생성한 값
publicKey.Exponent = Convert.FromBase64String(this.ResponseJson["exponentString"]); //JAVA에서 생성한 값
rsa.ImportParameters(publicKey);
publicKeyText = rsa.ToXmlString(false);
}
_postData.Add("securedUser", RSAEncrypt("아이디", publicKeyText));
_postData.Add("securedUserPwd", RSAEncrypt("패스워드", publicKeyText));
//_postData.Add("securedUser",
byte[] data = Encoding.UTF8.GetBytes(String.Join("&", _postData.Select(item => item.Key + "=" + item.Value)));
service = "http://localhost:8000//rest/login/LoginService.do";
this.GetPost(service, data, null);
}
private void GetGet(string service, byte[] data, CookieCollection cookie = null)
{
HttpWebRequest HttpWReq = (HttpWebRequest)WebRequest.Create(service);
HttpWReq.Method = "GET";
HttpWReq.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
using (HttpWebResponse httpResponse = (HttpWebResponse)HttpWReq.GetResponse())
{
if (httpResponse.StatusCode == HttpStatusCode.OK)
{
this.Cookies = httpResponse.Cookies;
Encoding encode;
if (httpResponse.CharacterSet.ToLower() == "utf-8") { encode = Encoding.UTF8; }
else { encode = Encoding.Default; }
using (var streamReader = new StreamReader(httpResponse.GetResponseStream(), encode))
{
this.ResponseString = streamReader.ReadToEnd(); //JAVA에서 전달한 값
this.ResponseJson = js.Deserialize<Dictionary<String, String>>(ResponseString);
}
}
}
}
private void GetPost(string service, byte[] data, CookieCollection cookie = null)
{
HttpWebRequest HttpWReq = (HttpWebRequest)WebRequest.Create(service);
HttpWReq.Method = "POST";
HttpWReq.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
HttpWReq.ContentLength = data.Length;
if (cookie != null)
{
if (HttpWReq.CookieContainer == null)
{
HttpWReq.CookieContainer = new CookieContainer();
}
HttpWReq.CookieContainer.Add(cookie);
}
deviceId = this.ResponseJson["deviceId"];
HttpWReq.Headers["deviceId"] = deviceId;
using (var stream = HttpWReq.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
using (HttpWebResponse httpResponse = (HttpWebResponse)HttpWReq.GetResponse())
{
if (httpResponse.StatusCode == HttpStatusCode.OK)
{
this.Cookies = httpResponse.Cookies;
Encoding encode;
if (httpResponse.CharacterSet.ToLower() == "utf-8") { encode = Encoding.UTF8; }
else { encode = Encoding.Default; }
using (var streamReader = new StreamReader(httpResponse.GetResponseStream(), encode))
{
this.ResponseString1 = streamReader.ReadToEnd();
}
}
}
}
// RSA 암호화
public string RSAEncrypt(string getValue, string pubKey)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(pubKey);
//암호화할 문자열을 UFT8인코딩
byte[] inbuf = (new UTF8Encoding()).GetBytes(getValue);
byte[] bytText = new byte[getValue.Length];
for (int i = 0; i < getValue.Length; i++)
{
bytText[i] = Convert.ToByte(getValue[i]);
}
byte[] bytEncText = rsa.Encrypt(bytText, false);
return BitConverter.ToString(bytEncText).Replace("-", string.Empty); ;
}
}
}
JAVA 코드
public class CryptoUtil {
private static class Singleton {
private static final CryptoUtil instance = new CryptoUtil();
}
private CryptoUtil() {}
public static CryptoUtil getInstance(){
return Singleton.instance;
}
/*
RSA 공개키와 개인키를 생성한다.
@param keyLength
/
@SuppressWarnings("finally")
public RSAKEYINFODTO generationRsaKey(int keyLength, boolean saveKeybit){
KeyPairGenerator kpgenerator = null;
RSAPublicKeySpec publicSpec = null;
KeyPair keyPair = null;
KeyFactory keyFactory = null;String publicKeyModulus = "";
String publicKeyExponent = "";RSAKEYINFODTO rsakeyDTO =null;
try {//RSA키 생성을 위한 초기 셋팅 //RSA키 생성기 인스턴스 생성 kpgenerator = KeyPairGenerator.getInstance("RSA"); //SecureRandom 랜덤값에 의한 키 초기화 SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); kpgenerator.initialize(keyLength, random); //RSA 키쌍(공개키, 개인키) 생성 keyPair = kpgenerator.genKeyPair(); keyFactory = KeyFactory.getInstance("RSA"); /* * RSA에서 PublicKey의 byte[]은 * modulus와 exponent의 * 좋바으로 이루어진 ASN.1 * 포맷(publickey.getEncoded()) */ //공개키(사용자에게 발급), 개인키(서버에 저장) PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); publicSpec = (RSAPublicKeySpec)keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class); publicKeyModulus = publicSpec.getModulus().toString(16); //공개 지수, 16진수 publicKeyExponent = publicSpec.getPublicExponent().toString(16); //공개키와 개인키정보를 저장하는 DTO객체를 생성 rsakeyDTO = new RSAKEYINFODTO(keyLength, publicKeyModulus, publicKeyExponent); //옵션값에 따라 키값을 바이너리 파일로 젖아하거나 //DTO객체에 셋 하거나 할 수 있다. if(saveKeybit) saveRsaPrivateKey(publicKeyModulus, privateKey); else rsakeyDTO.setPrivateKey(privateKey); rsakeyDTO.setPublicKey(publicKey);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e){
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
finally{return rsakeyDTO;
}
}
/*
Base64로 인코딩된 RSA로 암호화된
문자열을 복호화한다.
@param RSAKEYINFODTO keyDTO 객체
@param encStr Base64로 인코딩된 암호화된 문자열
@param saveKeybit PrivateKey 저장구분
@return
/
public String rsaDecrypt(RSAKEYINFODTO rsakeyDTO, String encStr, boolean saveKeybit)
throws NoSuchAlgorithmException
,NoSuchPaddingException
,FileNotFoundException,IOException
,ClassNotFoundException,InvalidKeyException
,IllegalBlockSizeException,BadPaddingException{
/*알고리즘 / 모드 /패딩 값 설정
알고리즘 : 인스턴스를 생성 할 알고리즘 명을 지정할 수 있다 현재는 RSA
모드 : 알고리즘 모드 지정(ECB,CBC,CCM,GCM,PCBC..)
패딩 : 알고리즘 패딩값지정 (PKCS1Padding..)
/
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");PrivateKey privateKey = null;
/*
비밀키를 가져온다
/
if(saveKeybit) privateKey = readRsaPrivateKey(rsakeyDTO.getModulus());
else privateKey = (PrivateKey)rsakeyDTO.getPrivateKey();cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] encryptedBytes = hexToByteArray(encStr);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
String decStr = new String(decryptedBytes,"UTF-8");return decStr;
}
}
public class RSAKEYINFODTO implements Serializable {
/**
*
*/
private static final long serialVersionUID = -7120303539138954172L;
private int keyLength; //RSA 키 길이
private String modulus; //공개키(Public Key)
private String exponent; //공개 지수
private String createdDt; //RSA 키 생성 날짜 시간
private String reqIpAddr; //로그인 IP
private String deviceId; //로그인 디바이스 id
private String loginGate; //로그인 디바이스 GATE
private PrivateKey privateKey; //로그인 개인키(Private Key)
private PublicKey publicKey; //로그인 공개키
public RSAKEYINFODTO(int keyLength, String publicKeyModulus, String publicKeyExponent) {
this.keyLength = keyLength;
this.modulus = publicKeyModulus;
this.exponent = publicKeyExponent;
SimpleDateFormat transFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
this.setCreatedDt(transFormat.format(new Date()));
}
public PrivateKey getPrivateKey() {
return privateKey;
}
public void setPrivateKey(PrivateKey privateKey){
this.privateKey = privateKey;
}
public String getModulus() {
return this.modulus;
}
public String getExponent(){
return this.exponent;
}
public void setDeviceId(String deviceId){
this.deviceId = deviceId;
}
public String getDeviceId() {
return this.deviceId;
}
public String getCreatedDt() {
return createdDt;
}
public void setCreatedDt(String createdDt) {
this.createdDt = createdDt;
}
public String getReqIpAddr() {
return reqIpAddr;
}
public void setReqIpAddr(String reqIpAddr) {
this.reqIpAddr = reqIpAddr;
}
public String getLoginGate() {
return loginGate;
}
public void setLoginGate(String loginGate) {
this.loginGate = loginGate;
}
public PublicKey getPublicKey() {
return publicKey;
}
public void setPublicKey(PublicKey publicKey) {
this.publicKey = publicKey;
}
}
사용 방법
JAVA에서
private static byte[] stripLeadingZeros(byte[] a)
{
int lastZero = -1;
for (int i = 0; i < a.length; i++)
{
if (a[i] == 0)
{
lastZero = i;
}
else
{
break;
}
}
lastZero++;
byte[] result = new byte[a.length-lastZero];
System.arraycopy(a, lastZero, result, 0, result.length);
return result;
}
RSAKEYINFODTO rsakeyInfo = encryptInstance.generationRsaKey(ConstantUtil.RSA_KEYLENGTH_512, false);
loginManger.setSession(session, rsakeyInfo);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec rsaPublicKey = (RSAPublicKeySpec)keyFactory.getKeySpec(rsakeyInfo.getPublicKey(), RSAPublicKeySpec.class); ;
byte[] modulusBytes = rsaPublicKey.getModulus().toByteArray();
modulusBytes = stripLeadingZeros(modulusBytes);
byte[] exponentBytes = rsaPublicKey.getPublicExponent().toByteArray();
String modulusString = Base64.encodeBase64String(modulusBytes); //C# 으로 전달할 값
String exponentString = Base64.encodeBase64String(exponentBytes); //C# 으로 전달할 값
C#에서 던질 값을 JAVA 에서복호화 하기
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, "개인키");
byte[] encryptedBytes = hexToByteArray("C#에서 암호화한 값");
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
String decStr = new String(decryptedBytes,"UTF-8"); //복호화
몇몇 코드는 안넣었는데 이해만 해서 직접 구현...
'.NET > ASP.NET' 카테고리의 다른 글
IHttpModule을 이용한 Gzip 적용 (0) | 2015.05.07 |
---|---|
Javascript Ajax Json 타입 주고 받는 WCF 구성 하기 (0) | 2014.09.04 |
runat="server" 들어간 input 태그에 cs 비하인드 데이터 바인딩 방법 (0) | 2014.07.10 |
Repeater 콘트롤 DataBind() 호출 시 흐름 (0) | 2014.06.02 |
runat=server 에 의한 ID, NAME 변경 막는법 (0) | 2014.04.17 |