# SSV Callback (Server-Side Verification)

## 서버에서 SSV 콜백 검증 과정

* SSV 콜백서버 등록시 서버로 아래와 같은 형태로 데이터가 들어오게 됩니다.
  * <https://callback\\_url?adnetwork=sampleadnetwork\\&adunit=sampleAdUnitID\\&customdata=sampleCustomData&><mark style="color:purple;">keyid=62031534a8bbd887dcca3d05</mark>\&rewardamount=5\&timestamp=1698114496119094000\&transactionid=119065000\_sampleAdUnitID\_sampleMediationID\&userid=sampleUserID&<mark style="color:red;">signature=MIGIAkIA4Urg1Hs7p9hLbZ-SLUemeluocwENpbiwxVmhEw9KtVGEcH6d7dRmIyAENHcTPDcPeJP\_YVAG9YO6K3cw24jUpD0CQgEZKN68mjOytwG1-H4VgYs3QXRWOBHx3D3bqYaWJvQwQ52X-OxsIDcxSuDo\_FyC1m2c7fxV7ybgNKLFmUuo7zN2qA==</mark>
  * 이때 query에서 signature와 나머지를 분리합니다
  * AD(X) 제공되는 [공개키](https://static.mediation.adxcorp.kr/reward/verifier-keys.json)를 통해 key 목록을 가져옵니다.
  * key 목록 중 query에 있던 keyid와 동일한 keyid를 가진 public key를 가져옵니다.
  * 해당 public key와 [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)를 지원하는 library로 signature 검증을 합니다.
  * 이 과정은 [애드몹 SSV 서버 검증](https://developers.google.com/admob/android/ssv?hl=ko#manual_verification_of_rewarded_ssv)과 비슷합니다.
  * 아래의 Java Security 또는 Tink Library 코드 샘플을 참고하여 진행해주세요.

### 1) Java Security 사용

```java
import java.security.*;

public void verifyUsingJavaSecurityPackage() {
    String publicKeyBase64 = "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAfu3ar6/tvJwXvDDIl9pfU0lPomGC6rxi37zbc6SYDl4bo7CRhm/sx/0hjitWXCRZddlv7b6O301PR/SZ9WVHpmgAcWeBxfAmEk7t4tyo1qStUYOApy4VZLaVsAnqklLhaM9qZp+79ck2UMxxD/QkClrTlxR+b/Sz42tD+Tv7YbvNZZs=";

    String signatureBase64 = "MIGIAkIA4Urg1Hs7p9hLbZ-SLUemeluocwENpbiwxVmhEw9KtVGEcH6d7dRmIyAENHcTPDcPeJP_YVAG9YO6K3cw24jUpD0CQgEZKN68mjOytwG1-H4VgYs3QXRWOBHx3D3bqYaWJvQwQ52X-OxsIDcxSuDo_FyC1m2c7fxV7ybgNKLFmUuo7zN2qA==";
    String dataToVerify = "adnetwork=sampleadnetwork&adunit=sampleAdUnitID&customdata=sampleCustomData&keyid=62031534a8bbd887dcca3d05&rewardamount=5&timestamp=1698114496119094000&transactionid=119065000_sampleAdUnitID_sampleMediationID&userid=sampleUserID";

    try {
        // Create a public key from the encoded bytes
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBase64));
        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

        // Initialize the Signature object for ECDSA
        Signature ecdsa = Signature.getInstance("SHA256withECDSA");
        ecdsa.initVerify(publicKey);

        // Update the Signature object with the data
        ecdsa.update(dataToVerify.getBytes("UTF-8"));

        // Verify the signature
        boolean isVerified = ecdsa.verify(Base64.getUrlDecoder().decode(signatureBase64));

        if (isVerified) {
            System.out.println("Signature is verified.");
        } else {
            System.out.println("Signature verification failed.");
        }
    } catch (Exception e) {
        System.out.println("e:" + e.toString());
    }
}
```

### 2) Tink Library 사용

```java
public void verifyUsingGoogleTinkLibrary() {
    String publicKeyBase64 = "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAfu3ar6/tvJwXvDDIl9pfU0lPomGC6rxi37zbc6SYDl4bo7CRhm/sx/0hjitWXCRZddlv7b6O301PR/SZ9WVHpmgAcWeBxfAmEk7t4tyo1qStUYOApy4VZLaVsAnqklLhaM9qZp+79ck2UMxxD/QkClrTlxR+b/Sz42tD+Tv7YbvNZZs=";

    String signatureBase64 = "MIGIAkIA4Urg1Hs7p9hLbZ-SLUemeluocwENpbiwxVmhEw9KtVGEcH6d7dRmIyAENHcTPDcPeJP_YVAG9YO6K3cw24jUpD0CQgEZKN68mjOytwG1-H4VgYs3QXRWOBHx3D3bqYaWJvQwQ52X-OxsIDcxSuDo_FyC1m2c7fxV7ybgNKLFmUuo7zN2qA==";
    String dataToVerify = "adnetwork=sampleadnetwork&adunit=sampleAdUnitID&customdata=sampleCustomData&keyid=62031534a8bbd887dcca3d05&rewardamount=5&timestamp=1698114496119094000&transactionid=119065000_sampleAdUnitID_sampleMediationID&userid=sampleUserID";

    try {
        ECPublicKey publicKey = EllipticCurves.getEcPublicKey(Base64.getDecoder().decode(publicKeyBase64));
        EcdsaVerifyJce verifier = new EcdsaVerifyJce(publicKey, Enums.HashType.SHA256, EllipticCurves.EcdsaEncoding.DER);
        verifier.verify(Base64.getUrlDecoder().decode(signatureBase64), dataToVerify.getBytes("UTF-8"));
    } catch (Exception e) {
        System.out.println("e:" + e.toString());
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://platform-business.gitbook.io/adx/appendix/ssv-callback-server-side-verification.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
