package api;

import com.sunyard.chsm.param.*;
import com.sunyard.chsm.utils.CodecUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.util.Collections;

/**
 * @author liulu
 * @since 2024/12/24
 */
@Slf4j
public class AsymKeyTest extends BaseTest {

    private static Long keyId;
    private static final byte[] plain = "hjsu234127qikqwasdqweqwewqdasdasdasdasdasndqqw13412as324".getBytes();
    private static final Long certKeyId = 1871443220005818369L;
    private static final String dn = "CN=cert-test,O=SYD,L=HZ,ST=ZJ,C=CN";

    private static final String enc_cert = "MIICdjCCAhqgAwIBAgINLGdqVePOjZMIDvBZqDAMBggqgRzPVQGDdQUAMEMxCzAJBgNVBAYTAkNOMQ0wCwYDVQQKDARCSkNBMQ0wCwYDVQQLDARCSkNBMRYwFAYDVQQDDA1URVNUU00yU1VCX1pYMB4XDTI0MTIyNDA1MzQxMVoXDTI1MTIyNDA2MzQxMVowSTELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAlpKMQswCQYDVQQHDAJIWjEMMAoGA1UECgwDU1lEMRIwEAYDVQQDDAljZXJ0LXRlc3QwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAQDJI7orEc8QVQMblzomR3SPeEqVJdfM46cxquj/JWJ318TZ0gZC1M9YPN9K5NDyaUwnExvGNpnz3PYxbs5nokXo4HqMIHnMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgM4MB0GA1UdDgQWBBSstrPACaBcow1prbZb2mkgzFOatzAfBgNVHSMEGDAWgBSqoPASv2D/pNLeAnE6J6XPnJ71KjA9BgNVHSAENjA0MDIGCSqBHIbvMgICBDAlMCMGCCsGAQUFBwIBFhdodHRwczovL3d3dy5iamNhLmNuL0NQUzBLBgNVHR8ERDBCMECgPqA8hjpodHRwczovL2NybC5pc2lnbmV0LmNuL2NybC9URVNUU00yU1VCX1pYL1RFU1RTTTJTVUJfWlguY3JsMAwGCCqBHM9VAYN1BQADSAAwRQIhAIJj1ERuVaKh+1YtDlE4kDwrK5ewMeH1ADnK+/7DBrwMAiAJ7J9HBqJkwul1yblnX52W4aQhPZt9LLDZZqJhjEd7Sg==";
    private static final String signAttachHsm = "MIIDPQYKKoEcz1UGAQQCAqCCAy0wggMpAgEBMQ4wDAYIKoEcz1UBgxEFADAYBgoqgRzPVQYBBAIBoAoECDEyMzQ1Njc4oIICMjCCAi4wggHSoAMCAQICBgGUAQHeQjAMBggqgRzPVQGDdQUAMEsxCzAJBgNVBAYTAkNOMQ4wDAYDVQQKEwVHTVNTTDEQMA4GA1UECxMHUEtJL1NNMjEaMBgGA1UEAxMRTWlkZGxlQ0EgZm9yIFRlc3QwIhgPMjAyNDEyMjUxNjAwMDBaGA8yMDI1MTIyNTE2MDAwMFowXTELMAkGA1UEBgwCQ04xCzAJBgNVBAgMAnpqMQswCQYDVQQHDAJoejEQMA4GA1UECgwHc3VueWFyZDEQMA4GA1UECwwHc3VueWFyZDEQMA4GA1UEAwwHdGVzdDEyMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABBNw7w5PxepQWwg5tfYoRIwilnqp01YvdY3ZnZD1ShHw6DX4f8cLblHagNazkOU9C5zeXvUWvtrcvZz5s92TLTGjgYkwgYYwGwYDVR0jBBQwEoAQ+X9VtCeUM2KmVspvzF0a/zAZBgNVHQ4EEgQQCR6s1jJA8ENWsIEo61LkMjAxBggrBgEFBQcBAQQlMCMwIQYIKwYBBQUHMAGGFWh0dHBzOi8vb2NzcC5nbXNzbC5jbjAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIAwDAMBggqgRzPVQGDdQUAA0gAMEUCIEaCtRZ8G4OgwhqI6NqxVwfUELvHS7ojkTGbImLX1ZkiAiEApFb7utbtgvL5hkV0Gj/k/CLY0vl+RbYSqAVoPtNEr1oxgcMwgcACAQEwVTBLMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFR01TU0wxEDAOBgNVBAsTB1BLSS9TTTIxGjAYBgNVBAMTEU1pZGRsZUNBIGZvciBUZXN0AgYBlAEB3kIwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARHMEUCIAt4OoCaP1/AmDZgMFWOfK046l+lNcfXdIYjhAw/nds4AiEA49yH+OAhi+4orHswRRzXE94x7kT9y7+l92kCjaS9EYA=";
    private static final String signDetachHsm = "MIIDMQYKKoEcz1UGAQQCAqCCAyEwggMdAgEBMQ4wDAYIKoEcz1UBgxEFADAMBgoqgRzPVQYBBAIBoIICMjCCAi4wggHSoAMCAQICBgGUAQHeQjAMBggqgRzPVQGDdQUAMEsxCzAJBgNVBAYTAkNOMQ4wDAYDVQQKEwVHTVNTTDEQMA4GA1UECxMHUEtJL1NNMjEaMBgGA1UEAxMRTWlkZGxlQ0EgZm9yIFRlc3QwIhgPMjAyNDEyMjUxNjAwMDBaGA8yMDI1MTIyNTE2MDAwMFowXTELMAkGA1UEBgwCQ04xCzAJBgNVBAgMAnpqMQswCQYDVQQHDAJoejEQMA4GA1UECgwHc3VueWFyZDEQMA4GA1UECwwHc3VueWFyZDEQMA4GA1UEAwwHdGVzdDEyMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABBNw7w5PxepQWwg5tfYoRIwilnqp01YvdY3ZnZD1ShHw6DX4f8cLblHagNazkOU9C5zeXvUWvtrcvZz5s92TLTGjgYkwgYYwGwYDVR0jBBQwEoAQ+X9VtCeUM2KmVspvzF0a/zAZBgNVHQ4EEgQQCR6s1jJA8ENWsIEo61LkMjAxBggrBgEFBQcBAQQlMCMwIQYIKwYBBQUHMAGGFWh0dHBzOi8vb2NzcC5nbXNzbC5jbjAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIAwDAMBggqgRzPVQGDdQUAA0gAMEUCIEaCtRZ8G4OgwhqI6NqxVwfUELvHS7ojkTGbImLX1ZkiAiEApFb7utbtgvL5hkV0Gj/k/CLY0vl+RbYSqAVoPtNEr1oxgcMwgcACAQEwVTBLMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFR01TU0wxEDAOBgNVBAsTB1BLSS9TTTIxGjAYBgNVBAMTEU1pZGRsZUNBIGZvciBUZXN0AgYBlAEB3kIwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARHMEUCIEzIJwjBsG6/2VemCJuQ0/eJhNS+Nwcz+7+WqJwlsgV5AiEA4ILu0NFEaM3IC4d9gAFswOZnACwYnKR2/gm9eZB4GsY=";
    private static final byte[] plainHsm = "12345678".getBytes();

    @BeforeAll
    public static void beforeAll() {
        keyId = execute("/key/gen", KeyCreateReq.builder().keyTemplateCode(asymKeyTemplate).genNumber(1).build(), Long.class);
        Assertions.assertTrue(keyId > 0);
    }

    @AfterAll
    public static void afterAll() {
        KeyManageReq keyManageReq = new KeyManageReq();
        keyManageReq.setIds(Collections.singletonList(keyId));
        execute("/key/disable", keyManageReq, Void.class);
        execute("/key/destroy", keyManageReq, Void.class);
    }

    @Test
    public void testExportKey() {
        ExportPubKeyReq req = new ExportPubKeyReq();
        req.setKeyId(keyId);
        ExportPubKeyResp exportPubKeyResp = execute("/asym/exportPubKey", req, ExportPubKeyResp.class);
        Assertions.assertNotNull(exportPubKeyResp);
        log.info("ExportPubKeyResp: {}", exportPubKeyResp.getPubKey());
    }

    @Test
    public void testRaw() {
        AsymSignRawReq signRawReq = new AsymSignRawReq();
        signRawReq.setKeyId(keyId);
        signRawReq.setPlainData(CodecUtils.encodeBase64(plain));
        AsymSignRawResp signRawResp = execute("/asym/sign/raw", signRawReq, AsymSignRawResp.class);
        Assertions.assertNotNull(signRawResp);
        log.info("AsymSignRawResp: {}", signRawResp);

        AsymVerifyRawReq verifyRawReq = new AsymVerifyRawReq();
        verifyRawReq.setKeyId(keyId);
        verifyRawReq.setKeyIndex(signRawResp.getKeyIndex());
        verifyRawReq.setPlainData(CodecUtils.encodeBase64(plain));
        verifyRawReq.setSignData(signRawResp.getSignData());
        VerifyResp verifyResp = execute("/asym/verify/raw", verifyRawReq, VerifyResp.class);
        Assertions.assertNotNull(verifyResp);
        log.info("verifyResp: {}", verifyResp);

        Assertions.assertTrue(verifyResp.getVerified());
    }

    @Test
    public void testAttach() {
        AsymSignP7Req signP7Req = new AsymSignP7Req();
        signP7Req.setSubject(dn);
        signP7Req.setPlainData(CodecUtils.encodeBase64(plain));
        AsymSignP7Resp signP7Resp = execute("/asym/sign/P7Attach", signP7Req, AsymSignP7Resp.class);
        Assertions.assertNotNull(signP7Resp);
        log.info("AsymSignP7Resp: {}", signP7Resp.getSignData());

        AsymVerifyP7Req verifyP7Req = new AsymVerifyP7Req();
        verifyP7Req.setSignData(signP7Resp.getSignData());
        VerifyResp verifyResp = execute("/asym/verify/P7Attach", verifyP7Req, VerifyResp.class);
        Assertions.assertNotNull(verifyResp);
        log.info("verifyResp: {}", verifyResp);

        Assertions.assertTrue(verifyResp.getVerified());
    }

    @Test
    public void testDetach() {
        AsymSignP7Req signP7Req = new AsymSignP7Req();
        signP7Req.setSubject(dn);
        signP7Req.setPlainData(CodecUtils.encodeBase64(plain));
        AsymSignP7Resp signP7Resp = execute("/asym/sign/P7Detach", signP7Req, AsymSignP7Resp.class);
        Assertions.assertNotNull(signP7Resp);
        log.info("AsymSignP7Resp: {}", signP7Resp.getSignData());

        AsymVerifyP7Req verifyP7Req = new AsymVerifyP7Req();
        verifyP7Req.setSignData(signP7Resp.getSignData());
        verifyP7Req.setPlainData(CodecUtils.encodeBase64(plain));
        VerifyResp verifyResp = execute("/asym/verify/P7Detach", verifyP7Req, VerifyResp.class);
        Assertions.assertNotNull(verifyResp);
        log.info("verifyResp: {}", verifyResp);

        Assertions.assertTrue(verifyResp.getVerified());
    }

    @Test
    public void testHsm() {
        AsymVerifyP7Req verifyP7Req = new AsymVerifyP7Req();
        verifyP7Req.setSignData(signAttachHsm);
        VerifyResp verifyResp = execute("/asym/verify/P7Attach", verifyP7Req, VerifyResp.class);
        Assertions.assertNotNull(verifyResp);
        log.info("verifyResp: {}", verifyResp);
        Assertions.assertTrue(verifyResp.getVerified());

        verifyP7Req.setSignData(signDetachHsm);
        verifyP7Req.setPlainData(CodecUtils.encodeBase64(plainHsm));
        VerifyResp verifyResp2 = execute("/asym/verify/P7Detach", verifyP7Req, VerifyResp.class);
        Assertions.assertNotNull(verifyResp2);
        log.info("verifyResp: {}", verifyResp2);
        Assertions.assertTrue(verifyResp2.getVerified());
    }

    @Test
    public void testEnvelopedData() {
        AsymEnvelopeSealReq sealReq = new AsymEnvelopeSealReq();
        sealReq.setEncCert(enc_cert);
        sealReq.setPlainData(CodecUtils.encodeBase64(plain));
        AsymEnvelopeSealResp sealResp = execute("/asym/envelope/seal", sealReq, AsymEnvelopeSealResp.class);
        Assertions.assertNotNull(sealResp);
        log.info("AsymEnvelopeSealResp: {}", sealResp);

        AsymEnvelopeUnsealReq unsealReq = new AsymEnvelopeUnsealReq();
        unsealReq.setEnvelopeData(sealResp.getEnvelopeData());
        AsymEnvelopeUnsealResp unsealResp = execute("/asym/envelope/unseal", unsealReq, AsymEnvelopeUnsealResp.class);
        Assertions.assertNotNull(unsealResp);
        log.info("AsymEnvelopeUnsealResp: {}", unsealResp);
        log.info("AsymEnvelopeUnsealResp: {}", new String(CodecUtils.decodeBase64(unsealResp.getPlainData())));

        Assertions.assertArrayEquals(plain, CodecUtils.decodeBase64(unsealResp.getPlainData()));
    }

    @Test
    public void testSignedEnvelopedData() {
        AsymEnvelopeSealReq sealReq = new AsymEnvelopeSealReq();
        sealReq.setSignSubject(dn);
        sealReq.setEncCert(enc_cert);
        sealReq.setPlainData(CodecUtils.encodeBase64(plain));
        AsymEnvelopeSealResp sealResp = execute("/asym/signedEnvelope/seal", sealReq, AsymEnvelopeSealResp.class);
        Assertions.assertNotNull(sealResp);
        log.info("SignedEnvelopeEnvelopeSealResp: {}", sealResp);

        AsymEnvelopeUnsealReq unsealReq = new AsymEnvelopeUnsealReq();
        unsealReq.setEnvelopeData(sealResp.getEnvelopeData());
        AsymEnvelopeUnsealResp unsealResp = execute("/asym/signedEnvelope/unseal", unsealReq, AsymEnvelopeUnsealResp.class);
        Assertions.assertNotNull(unsealResp);
        log.info("AsymEnvelopeUnsealResp: {}", unsealResp);
        log.info("AsymEnvelopeUnsealResp: {}", new String(CodecUtils.decodeBase64(unsealResp.getPlainData())));

        Assertions.assertArrayEquals(plain, CodecUtils.decodeBase64(unsealResp.getPlainData()));
    }


}
