Skip to content

Commit 368a0af

Browse files
kaiferroot
authored and
root
committed
RELEASE
1 parent 9fd67fa commit 368a0af

File tree

6 files changed

+208
-72
lines changed

6 files changed

+208
-72
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ JAVA 1.8버전 사용자들을 위한 세션키 발급 및 개인정보 암복
66

77
예시)
88
```
9-
<version>0.0.12</version>
9+
<version>0.0.13</version>
1010
```
1111

1212
pom.xml 을 사용하시면 아래와 같이 추가해주세요.

build.gradle

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
group 'com.github.toss'
9-
version '0.0.12'
9+
version '0.0.13'
1010

1111
sourceCompatibility = JavaVersion.VERSION_1_6
1212
targetCompatibility = JavaVersion.VERSION_1_6
@@ -25,6 +25,7 @@ repositories {
2525

2626
dependencies {
2727
implementation 'commons-codec:commons-codec:1.15'
28+
implementation 'org.bouncycastle:bcpkix-jdk18on:1.77'
2829
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
2930
testImplementation 'javax.json:javax.json-api:1.1.4'
3031
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package im.toss.cert.sdk;
2+
3+
import org.bouncycastle.cert.jcajce.JcaCertStoreBuilder;
4+
import org.bouncycastle.cms.CMSException;
5+
import org.bouncycastle.cms.CMSSignedData;
6+
7+
import java.security.GeneralSecurityException;
8+
import java.security.cert.CertStore;
9+
import java.security.cert.CertStoreException;
10+
import java.security.cert.Certificate;
11+
import java.security.cert.CertificateEncodingException;
12+
import java.util.Collection;
13+
14+
public class PKCS7CertificateExtractor {
15+
public static String extractCertificate(String pkcs7Data) {
16+
try {
17+
CMSSignedData signedData = new CMSSignedData(Base64Utils.decode(pkcs7Data));
18+
CertStore certStore = new JcaCertStoreBuilder().addCertificates(signedData.getCertificates()).build();
19+
Collection<? extends Certificate> certificates = certStore.getCertificates(null);
20+
return convertToPem(certificates.iterator().next());
21+
} catch (CMSException e) {
22+
throw new RuntimeException(e.getCause());
23+
} catch (CertificateEncodingException e) {
24+
throw new RuntimeException(e.getCause());
25+
} catch (CertStoreException e) {
26+
throw new RuntimeException(e.getCause());
27+
} catch (GeneralSecurityException e) {
28+
throw new RuntimeException(e.getCause());
29+
}
30+
}
31+
32+
private static String convertToPem(Certificate certificate) throws CertificateEncodingException {
33+
String pemCertPre = "-----BEGIN CERTIFICATE-----\n";
34+
String pemCertPost = "\n-----END CERTIFICATE-----";
35+
String pemCert = Base64Utils.encodeToString(certificate.getEncoded());
36+
return pemCertPre + pemCert + pemCertPost;
37+
}
38+
}

src/main/java/im/toss/cert/sdk/TossCertSessionGenerator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import java.util.UUID;
1010

1111
public class TossCertSessionGenerator {
12-
private final static String version = "v1_0.0.12";
12+
private final static String version = "v1_0.0.13";
1313
private final static String publicKey = "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoVdxG0Qi9pip46Jw9ImSlPVD8+L2mM47ey6EZna7D7utgNdh8Tzkjrm1Yl4h6kPJrhdWvMIJGS51+6dh041IXcJEoUquNblUEqAUXBYwQM8PdfnS12SjlvZrP4q6whBE7IV1SEIBJP0gSK5/8Iu+uld2ctJiU4p8uswL2bCPGWdvVPltxAg6hfAG/ImRUKPRewQsFhkFvqIDCpO6aeaR10q6wwENZltlJeeRnl02VWSneRmPqqypqCxz0Y+yWCYtsA+ngfZmwRMaFkXcWjaWnvSqqV33OAsrQkvuBHWoEEkvQ0P08+h9Fy2+FhY9TeuukQ2CVFz5YyOhp25QtWyQI+IaDKk+hLxJ1APR0c3tmV0ANEIjO6HhJIdu2KQKtgFppvqSrZp2OKtI8EZgVbWuho50xvlaPGzWoMi9HSCb+8ARamlOpesxHH3O0cTRUnft2Zk1FHQb2Pidb2z5onMEnzP2xpTqAIVQyb6nMac9tof5NFxwR/c4pmci+1n8GFJIFN18j2XGad1mNyio/R8LabqnzNwJC6VPnZJz5/pDUIk9yKNOY0KJe64SRiL0a4SNMohtyj6QlA/3SGxaEXb8UHpophv4G9wN1CgfyUamsRqp8zo5qDxBvlaIlfkqJvYPkltj7/23FHDjPi8q8UkSiAeu7IV5FTfB5KsiN8+sGSMCAwEAAQ==";
1414

1515
private final RSACipher rsaCipher;

src/test/java/im/toss/cert/sdk/ExampleTest.java

+80-69
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@
66
import javax.json.Json;
77
import javax.json.JsonObject;
88
import javax.json.JsonReader;
9+
import java.io.IOException;
910
import java.io.InputStream;
1011
import java.io.OutputStreamWriter;
1112
import java.io.StringReader;
1213
import java.net.HttpURLConnection;
1314
import java.net.URL;
1415
import java.util.Scanner;
1516

16-
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
import static org.junit.jupiter.api.Assertions.assertTrue;
1718

1819
@Disabled // 실행전에 해당라인을 삭제해주세요.
1920
class ExampleTest {
2021
// 0. 세션 생성기를 사전에 1회만 생성해 주세요.
2122
TossCertSessionGenerator tossCertSessionGenerator = new TossCertSessionGenerator();
2223

24+
final String accessToken = "eyJraWQiOiJjZXJ0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJ0ZXN0X2E4ZTIzMzM2ZDY3M2NhNzA5MjJiNDg1ZmU4MDZlYjJkIiwiYXVkIjoidGVzdF9hOGUyMzMzNmQ2NzNjYTcwOTIyYjQ4NWZlODA2ZWIyZCIsIm5iZiI6MTcwOTAyMDA5OSwic2NvcGUiOlsiY2EiXSwiaXNzIjoiaHR0cHM6Ly9jZXJ0LnRvc3MuaW0iLCJleHAiOjE3NDA1NTYwOTksImlhdCI6MTcwOTAyMDA5OSwianRpIjoiZDc3NmUxZmEtZmNkMy00MDE4LTg2MGMtZDA0NTY0YmUxY2U5In0.hQDc7eeY6-a-0tLfcsAO_Tejbmu_Sd7f80P90NtTy6T4HjEUQNji13sMdkhPeibnonE0E8d4fdsyFy2J2KQFLIqFNjV-jPypjm9XcF2yUBwBfG7Jq7k1BBuigPXTN1NistNpnE24F0nNlMzsGZi72YePIFEayFi_SQN5GUwZ9MZbQenGA9sKct0heqKxQj7wuyELgvT7dCFtZ5EU_C_DDhvgtyauGvD4ubtxj2_-SskAnr54LZhW-cDF-rdsAD9knbhcnscpZKXnGVNlXbQzgrVfWNEYlJeZ9bwagdgYh67VrC8SNBoGPuXsKU4eUV17lh_TwB9M2lPkBJLwgaJVgA";
25+
2326
@Test
2427
void request() throws Exception {
2528
// 1. 개인정보가 포함되어 있는 인증요청 API 호출 전에 세션을 생성해 주세요.
@@ -34,105 +37,113 @@ void request() throws Exception {
3437
String encryptedUserBirthday = tossCertSession.encrypt(userBirthday);
3538

3639
// 3. 인증요청 API 를 호출해주세요.
37-
URL url = new URL("https://cert.toss.im/api/v2/sign/user/auth/request");
38-
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
39-
httpConn.setRequestMethod("POST");
40-
41-
httpConn.setRequestProperty("Authorization", "Bearer eyJraWQiOiJjZXJ0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJ0ZXN0X2E4ZTIzMzM2ZDY3M2NhNzA5MjJiNDg1ZmU4MDZlYjJkIiwiYXVkIjoidGVzdF9hOGUyMzMzNmQ2NzNjYTcwOTIyYjQ4NWZlODA2ZWIyZCIsIm5iZiI6MTY0OTIyMjk3OCwic2NvcGUiOlsiY2EiXSwiaXNzIjoiaHR0cHM6XC9cL2NlcnQudG9zcy5pbSIsImV4cCI6MTY4MDc1ODk3OCwiaWF0IjoxNjQ5MjIyOTc4LCJqdGkiOiI4MDNjNDBjOC1iMzUxLTRmOGItYTIxNC1iNjc5MmNjMzBhYTcifQ.cjDZ0lAXbuf-KAgi3FlG1YGxvgvT3xrOYKDTstfbUz6CoNQgvd9TqI6RmsGZuona9jIP6H12Z1Xb07RIfAVoTK-J9iC5_Yp8ZDdcalsMNj51pPP8wso86rn-mKsrx1J5Rdi3GU58iKt0zGr4KzqSxUJkul9G4rY03KInwvl692HU19kYA9y8uTI4bBX--UPfQ02G0QH9HGTPHs7lZsISDtyD8sB2ikz5p7roua7U467xWy4BnRleCEWO2uUaNNGnwd7SvbjhmsRZqohs9KzDUsFjVhSiRNdHL53XJQ5zFHwDF92inRZFLu6Dw8xttPtNHwAD1kT84uXJcVMfEHtwkQ");
42-
httpConn.setRequestProperty("Content-Type", "application/json");
43-
httpConn.setDoOutput(true);
44-
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
45-
/* json
46-
{
47-
"requestType": "USER_PERSONAL",
48-
"triggerType": "PUSH",
49-
"sessionKey": tossCertSession.getSessionKey(),
50-
"userName": encryptedUserName,
51-
"userPhone": encryptedUserPhone,
52-
"userBirthday": encryptedUserBirthday
53-
}
54-
*/
40+
/* json
41+
{
42+
"requestType": "USER_PERSONAL",
43+
"triggerType": "PUSH",
44+
"sessionKey": tossCertSession.getSessionKey(),
45+
"userName": encryptedUserName,
46+
"userPhone": encryptedUserPhone,
47+
"userBirthday": encryptedUserBirthday
48+
}
49+
*/
5550
String requestBody = Json.createObjectBuilder()
56-
.add("requestType", "USER_PERSONAL")
57-
.add("triggerType", "PUSH")
58-
// 3.1 세션키를 넣어주세요.
59-
.add("sessionKey", tossCertSession.getSessionKey())
60-
// 3.2 tossCertSession 로 암호화된 개인정보를 넣어주세요.
61-
.add("userName", encryptedUserName)
62-
.add("userPhone", encryptedUserPhone)
63-
.add("userBirthday", encryptedUserBirthday)
64-
.build()
65-
.toString();
66-
writer.write(requestBody);
67-
writer.flush();
68-
writer.close();
69-
70-
httpConn.getOutputStream().close();
71-
InputStream responseStream = httpConn.getResponseCode() == 200
72-
? httpConn.getInputStream()
73-
: httpConn.getErrorStream();
74-
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
75-
String response = s.hasNext() ? s.next() : "";
51+
.add("requestType", "USER_PERSONAL")
52+
.add("triggerType", "PUSH")
53+
// 3.1 세션키를 넣어주세요.
54+
.add("sessionKey", tossCertSession.getSessionKey())
55+
// 3.2 tossCertSession 로 암호화된 개인정보를 넣어주세요.
56+
.add("userName", encryptedUserName)
57+
.add("userPhone", encryptedUserPhone)
58+
.add("userBirthday", encryptedUserBirthday)
59+
.build()
60+
.toString();
61+
62+
JsonObject responseObject = postUrl("https://cert.toss.im/api/v2/sign/user/auth/request", requestBody);
7663

77-
JsonReader responseReader = Json.createReader(new StringReader(response));
78-
JsonObject responseObject = responseReader.readObject();
7964
System.out.println("\n--------------------------- 인증 요청 결과 -------------------------------------");
8065
System.out.println("인증 txId: " + responseObject.getJsonObject("success").getString("txId"));
8166
System.out.println("----------------------------------------------------------------------------\n");
82-
assertEquals(1, 1);
8367
}
8468

8569
// 결과호출을 하기전에 토스앱에서 인증을 완료해 주세요.
8670

8771
@Test
8872
void result() throws Exception {
8973
// 0. 인증 요청 결과에서 응답받은 인증 txId 로 변경한 후 테스트 해주세요.
90-
String txId = "2122cb6d-46f9-4e72-86eb-3f71c3c97507";
74+
String txId = "인증 txId";
9175

9276
// 1. 인증 결과 조회 API 호출 전에 세션을 생성해 주세요.
9377
TossCertSession tossCertSession = tossCertSessionGenerator.generate();
9478

9579
// 2. 인증요청 API 를 호출해주세요.
96-
URL url = new URL("https://cert.toss.im/api/v2/sign/user/auth/result");
80+
/* json
81+
{
82+
"sessionKey": tossCertSession.getSessionKey(),
83+
"txId": txId
84+
}
85+
*/
86+
String requestBody = Json.createObjectBuilder()
87+
// 2.1 세션키를 넣어주세요.
88+
.add("sessionKey", tossCertSession.getSessionKey())
89+
// 2.2 인증 요청 결과의 txId 를 넣어주세요.
90+
.add("txId", txId)
91+
.build()
92+
.toString();
93+
94+
JsonObject responseObject = postUrl("https://cert.toss.im/api/v2/sign/user/auth/result", requestBody);
95+
96+
// 3. 결과를 복호화 합니다.
97+
String encryptedCi = responseObject.getJsonObject("success").getJsonObject("personalData").getString("ci");
98+
String ci = tossCertSession.decrypt(encryptedCi);
99+
System.out.println("\n--------------------------- 인증 결과 조회 CI ----------------------------------");
100+
System.out.println("복호화 된 CI: " + ci);
101+
System.out.println("----------------------------------------------------------------------------\n");
102+
103+
// 4. 인증서 유효성을 검사합니다.
104+
String signature = responseObject.getJsonObject("success").getString("signature");
105+
String pemCertificate = PKCS7CertificateExtractor.extractCertificate(signature);
106+
107+
/* json
108+
{
109+
"certificate": pemCertificate
110+
}
111+
*/
112+
requestBody = Json.createObjectBuilder()
113+
// 2.1 세션키를 넣어주세요.
114+
.add("certificate", pemCertificate)
115+
// 2.2 인증 요청 결과의 txId 를 넣어주세요.
116+
.build()
117+
.toString();
118+
119+
responseObject = postUrl("https://cert.toss.im/api/v1/certificate/validate", requestBody);
120+
121+
assertTrue(responseObject.getJsonObject("success").getBoolean("valid"));
122+
assertTrue(responseObject.getJsonObject("success").getBoolean("enabled"));
123+
}
124+
125+
private JsonObject postUrl(String urlString, String requestBody) throws IOException {
126+
URL url = new URL(urlString);
97127
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
98128
httpConn.setRequestMethod("POST");
99129

100-
httpConn.setRequestProperty("Authorization", "Bearer eyJraWQiOiJjZXJ0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJ0ZXN0X2E4ZTIzMzM2ZDY3M2NhNzA5MjJiNDg1ZmU4MDZlYjJkIiwiYXVkIjoidGVzdF9hOGUyMzMzNmQ2NzNjYTcwOTIyYjQ4NWZlODA2ZWIyZCIsIm5iZiI6MTY0OTIyMjk3OCwic2NvcGUiOlsiY2EiXSwiaXNzIjoiaHR0cHM6XC9cL2NlcnQudG9zcy5pbSIsImV4cCI6MTY4MDc1ODk3OCwiaWF0IjoxNjQ5MjIyOTc4LCJqdGkiOiI4MDNjNDBjOC1iMzUxLTRmOGItYTIxNC1iNjc5MmNjMzBhYTcifQ.cjDZ0lAXbuf-KAgi3FlG1YGxvgvT3xrOYKDTstfbUz6CoNQgvd9TqI6RmsGZuona9jIP6H12Z1Xb07RIfAVoTK-J9iC5_Yp8ZDdcalsMNj51pPP8wso86rn-mKsrx1J5Rdi3GU58iKt0zGr4KzqSxUJkul9G4rY03KInwvl692HU19kYA9y8uTI4bBX--UPfQ02G0QH9HGTPHs7lZsISDtyD8sB2ikz5p7roua7U467xWy4BnRleCEWO2uUaNNGnwd7SvbjhmsRZqohs9KzDUsFjVhSiRNdHL53XJQ5zFHwDF92inRZFLu6Dw8xttPtNHwAD1kT84uXJcVMfEHtwkQ");
130+
httpConn.setRequestProperty("Authorization", "Bearer " + accessToken);
101131
httpConn.setRequestProperty("Content-Type", "application/json");
102132
httpConn.setDoOutput(true);
103133
OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
104-
/* json
105-
{
106-
"sessionKey": tossCertSession.getSessionKey(),
107-
"txId": txId
108-
}
109-
*/
110-
String requestBody = Json.createObjectBuilder()
111-
// 2.1 세션키를 넣어주세요.
112-
.add("sessionKey", tossCertSession.getSessionKey())
113-
// 2.2 인증 요청 결과의 txId 를 넣어주세요.
114-
.add("txId", txId)
115-
.build()
116-
.toString();
134+
117135
writer.write(requestBody);
118136
writer.flush();
119137
writer.close();
120138

121139
httpConn.getOutputStream().close();
122140
InputStream responseStream = httpConn.getResponseCode() == 200
123-
? httpConn.getInputStream()
124-
: httpConn.getErrorStream();
141+
? httpConn.getInputStream()
142+
: httpConn.getErrorStream();
125143
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
126144
String response = s.hasNext() ? s.next() : "";
127-
JsonReader responseReader = Json.createReader(new StringReader(response));
128-
JsonObject responseObject = responseReader.readObject();
129145

130-
// 3. 결과를 복호화 합니다.
131-
String encryptedCi = responseObject.getJsonObject("success").getJsonObject("personalData").getString("ci");
132-
String ci = tossCertSession.decrypt(encryptedCi);
133-
System.out.println("\n--------------------------- 인증 결과 조회 CI ----------------------------------");
134-
System.out.println("복호화 된 CI: " + ci);
135-
System.out.println("----------------------------------------------------------------------------\n");
136-
assertEquals(1, 1);
146+
JsonReader responseReader = Json.createReader(new StringReader(response));
147+
return responseReader.readObject();
137148
}
138149
}

0 commit comments

Comments
 (0)