지돌이의 블로그 입니다!

https://github.com/jc-lab/openssl-fips-cmake

 

jc-lab/openssl-fips-cmake

Contribute to jc-lab/openssl-fips-cmake development by creating an account on GitHub.

github.com

참고~

Comment +0

C++ & libuv & uvw (C++ libuv wrapper library) 으로 http server을 구현했습니다.

 

Spring-boot의 RequestMapping과 같은 기능을 구현해놓아서 URL에 대한 접근이 용이합니다.

 

#include <iostream>

#include <uvw/loop.hpp>
#include <jshttpserver/server.hpp>
#include <jshttpserver/http_request.hpp>

#pragma comment(lib, "libuv.lib")

int main() {
    auto loop = uvw::Loop::getDefault();

    std::shared_ptr<jshttpserver::Server> server(jshttpserver::Server::create(loop));

    server->requestMapping(jshttpserver::METHOD_ALL, "/api/test", [](jshttpserver::HttpRequest &req, jshttpserver::HttpResponse &res) {
      std::cout << "requestMapping FOUND :: /api/test" << std::endl;
      std::cout << "\tsearch[ " << req.url_search << " ]" << std::endl;
    });

    server->requestMapping(jshttpserver::METHOD_ALL, "/api/test2/{v1}/{v2}", [](jshttpserver::HttpRequest &req, jshttpserver::HttpResponse &res) {
      std::cout << "requestMapping FOUND :: /api/test2/{v1}/{v2}" << std::endl;
      std::cout << "\tsearch[ " << req.url_search << " ]" << std::endl;
    });

    server->requestMapping(jshttpserver::METHOD_ALL, "/api/test3/{v3:.+}", [](jshttpserver::HttpRequest &req, jshttpserver::HttpResponse &res) {
      std::cout << "requestMapping FOUND :: /api/test3/{v3:.+}" << std::endl;
      std::cout << "\tsearch[ " << req.url_search << " ]" << std::endl;
    });

    server->documentRootMapping("/docs/", [](jshttpserver::HttpRequest &req, jshttpserver::HttpResponse &res) {
      std::cout << "documentRootMapping FOUND :: /docs/ :: path = " << req.doc_path_name << std::endl;
      std::cout << "\tpath_name[ " << req.doc_path_name << " ], search[ " << req.url_search << " ]" << std::endl;
    });

    server->documentRootMapping("/doxs", [](jshttpserver::HttpRequest &req, jshttpserver::HttpResponse &res) {
      std::cout << "documentRootMapping FOUND :: /doxs :: path = " << req.doc_path_name << std::endl;
      std::cout << "\tpath_name[ " << req.doc_path_name << " ], search[ " << req.url_search << " ]" << std::endl;
    });

    server->addListen(8887);

    loop->run();
    return 0;
}

 

https://github.com/jc-lab/jshttpserver-uvw.git

 

jc-lab/jshttpserver-uvw

Contribute to jc-lab/jshttpserver-uvw development by creating an account on GitHub.

github.com

 

Comment +0

https://github.com/jc-lab/jcp

지금은 mbedtls만 지원. HAS_MBEDTLS 혹은 HAS_MBEDCRYPTO 전처리기 필요

예제 :

#include <stdio.h>
#include <iostream>

#ifdef _DEBUG
#pragma comment(lib, "mbedcryptod.lib")
#pragma comment(lib, "mbedx509d.lib")
#else
#pragma comment(lib, "mbedcrypto.lib")
#pragma comment(lib, "mbedx509.lib")
#endif

#include <jcp/provider.hpp>
#include <jcp/asym_key.hpp>

#include <jcp/cipher.hpp>
#include <jcp/gcm_param_spec.hpp>
#include <jcp/message_digest.hpp>
#include <jcp/mac.hpp>
#include <jcp/key_agreement.hpp>
#include <jcp/signature.hpp>

using namespace jcp;

void printHexBytes(const void *ptr, int len) {
    const unsigned char* cptr = (const unsigned char*)ptr;
    int i;
    for (i = 0; i < len; i++) {
        printf("%02x ", cptr[i]);
    }
    printf("\n");
}

int main() {
    // Hmac Test
    if (0)
    {
        std::unique_ptr<Mac> md(Mac::getInstance("HmacSHA256"));
        SecretKey macKey((const unsigned char*)"abcd", 4);
        md->init(&macKey);
        md->update("abcdefg", 7);
        md->update("1234", 4);
        std::unique_ptr<Result<Buffer>> digest = md->digest();
        printf("doFinal : "); printHexBytes(&digest->result().data()[0], digest->result().size());

        // 39646d8e7cc8f48310089caa891aaede962a054aac9b38feeafac6d00ea1c85c
        // TEST OK
    }

    // Message Digest SHA test
    if (0)
    {
        std::unique_ptr<MessageDigest> md(MessageDigest::getInstance("SHA-256"));
        md->update("abcdefg", 7);
        md->update("1234", 4);
        std::unique_ptr<Result<Buffer>> digest = md->digest();
        printf("doFinal : "); printHexBytes(&digest->result().data()[0], digest->result().size());

        // a5fece454cbf03ada21e1de86dbc705af674ae029dac95a027b5ce5f9bdfd10f
        // TEST OK
    }

    // AES/GCM Test
    if (1)
    {
        std::vector<unsigned char> ciphertext;

        {
            std::unique_ptr<Cipher> cipher(Cipher::getInstance("AES/GCM/NoPadding"));
            SecretKey encKey((const unsigned char*)"0123456789abcdef", 16);
            std::unique_ptr<Result<Buffer>> result_with_buffer;

            cipher->init(Cipher::ENCRYPT_MODE, &encKey, GCMParameterSpec::create(128, (uint8_t*)"0000000000000000", 16).get());
            cipher->updateAAD("auth_1234", 9);
            result_with_buffer = cipher->update("abcd", 4);
            std::cout << "ENCRYPTING : " << std::endl;
            if (result_with_buffer->result().size() > 0) {
                printHexBytes(&result_with_buffer->result().data()[0], result_with_buffer->result().size());
                ciphertext.insert(ciphertext.end(), result_with_buffer->result().data(), result_with_buffer->result().data() + result_with_buffer->result().size());
            }
            result_with_buffer = cipher->doFinal();
            std::cout << "ENCRYPTING(FINAL) : " << std::endl;
            if (result_with_buffer->result().size() > 0) {
                printHexBytes(&result_with_buffer->result().data()[0], result_with_buffer->result().size());
                ciphertext.insert(ciphertext.end(), result_with_buffer->result().data(), result_with_buffer->result().data() + result_with_buffer->result().size());
            }
        }

        std::cout << "CIPHER TEXT : " << std::endl;
        printHexBytes(ciphertext.data(), ciphertext.size());
        // ad0f07ed e997dd8608e0205be4f5f8621fcf652e
        // ENCRYPTION TEST OK


        {
            std::unique_ptr<Cipher> cipher(Cipher::getInstance("AES/GCM/NoPadding"));
            SecretKey encKey((const unsigned char*)"0123456789abcdef", 16);
            std::unique_ptr<Result<Buffer>> result_with_buffer;

            cipher->init(Cipher::DECRYPT_MODE, &encKey, GCMParameterSpec::create(128, (uint8_t*)"0000000000000000", 16).get());
            cipher->updateAAD("auth_1234", 9);
            result_with_buffer = cipher->update(ciphertext.data(), ciphertext.size());
            std::cout << "DECRYPTING : " << std::endl;
            if (result_with_buffer->result().size() > 0) {
                printHexBytes(&result_with_buffer->result().data()[0], result_with_buffer->result().size());
                ciphertext.insert(ciphertext.end(), result_with_buffer->result().data(), result_with_buffer->result().data() + result_with_buffer->result().size());
            }
            result_with_buffer = cipher->doFinal();
            std::cout << "DECRYPTING(FINAL) : excep(" << (result_with_buffer->exception() ? "true" : "false") << ") : " << std::endl;
            printHexBytes(&result_with_buffer->result().data()[0], result_with_buffer->result().size());
        }

        // DECRYPTION TEST OK
    }

    // RSA Encryption Test
    if (0)
    {
        std::unique_ptr<Cipher> cipher(Cipher::getInstance("RSA/ECB/OEAPPadding"));

        jcp::AsymKeyImpl prikey;
        jcp::AsymKeyImpl pubkey;
        uint8_t bin_pubkey[] = { 0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01,0x00,0xc7,0x85,0xb3,0xae,0x8b,0x52,0x80,0xe3,0xb5,0x2d,0x55,0x01,0x2d,0xa8,0x58,0x1c,0x10,0xf8,0x3a,0xe2,0xc9,0xa7,0xbd,0x76,0x4a,0x8d,0xe1,0x3d,0xae,0x46,0xe1,0x7b,0xee,0x6b,0x1d,0x89,0xc8,0xc3,0x43,0x28,0x0c,0xcc,0xb0,0x2b,0x7b,0x25,0x51,0x00,0x54,0x30,0xda,0x72,0x1b,0x72,0x46,0x54,0xc8,0x26,0xef,0x1c,0x8a,0x13,0xb4,0xcc,0xaf,0xd2,0x06,0x1e,0xfa,0x24,0xe3,0xb8,0x5b,0xd4,0x00,0x47,0xdd,0x1e,0x8a,0xc2,0xcb,0xf4,0x31,0x1e,0x8c,0xf5,0x9b,0x90,0x64,0xc5,0x02,0x02,0xb3,0x54,0x9d,0x38,0x44,0x78,0x45,0x42,0xa2,0x1f,0x22,0x06,0x87,0xba,0xef,0x44,0x7c,0x50,0xca,0xd5,0x08,0x8d,0xa0,0xf6,0x31,0xda,0x12,0xd5,0x0f,0xe3,0xd3,0x38,0x34,0x99,0x3a,0x46,0xe5,0xe8,0xa5,0x80,0x1c,0x0e,0xd6,0xd3,0x63,0x2b,0x62,0xf7,0x99,0x57,0xba,0xa8,0x2f,0x6f,0x84,0x96,0xbd,0xfe,0x3b,0x47,0x68,0x87,0x33,0x57,0x41,0x98,0xfd,0xde,0xe5,0x72,0xa0,0x2c,0xc2,0x00,0x87,0x5f,0x97,0xd9,0xe6,0xdf,0xe4,0x33,0x33,0xe0,0x4f,0x51,0x16,0xd1,0xd1,0x55,0xe2,0xa5,0x97,0x8a,0x5e,0x60,0x13,0x73,0xae,0x73,0x05,0x7b,0x7c,0x95,0x0c,0xff,0x27,0x6d,0x43,0xb1,0x3a,0x5c,0xa6,0x0c,0x01,0x72,0x7f,0x81,0xb0,0xa1,0x99,0x9c,0x9c,0xeb,0x7e,0x48,0xe1,0x09,0x18,0x61,0x45,0xfc,0xb1,0xb2,0x33,0x82,0x26,0xcc,0x42,0xfe,0x8a,0x54,0x35,0xf8,0x4c,0x9a,0x68,0x8d,0x67,0xc5,0xb3,0x36,0x83,0x9d,0x5a,0x11,0x11,0x81,0xcc,0xe5,0xb8,0xa5,0xb4,0xef,0x02,0x03,0x01,0x00,0x01 };
        uint8_t bin_prikey[] = { 0x30,0x82,0x04,0xbf,0x02,0x01,0x00,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x04,0xa9,0x30,0x82,0x04,0xa5,0x02,0x01,0x00,0x02,0x82,0x01,0x01,0x00,0xc7,0x85,0xb3,0xae,0x8b,0x52,0x80,0xe3,0xb5,0x2d,0x55,0x01,0x2d,0xa8,0x58,0x1c,0x10,0xf8,0x3a,0xe2,0xc9,0xa7,0xbd,0x76,0x4a,0x8d,0xe1,0x3d,0xae,0x46,0xe1,0x7b,0xee,0x6b,0x1d,0x89,0xc8,0xc3,0x43,0x28,0x0c,0xcc,0xb0,0x2b,0x7b,0x25,0x51,0x00,0x54,0x30,0xda,0x72,0x1b,0x72,0x46,0x54,0xc8,0x26,0xef,0x1c,0x8a,0x13,0xb4,0xcc,0xaf,0xd2,0x06,0x1e,0xfa,0x24,0xe3,0xb8,0x5b,0xd4,0x00,0x47,0xdd,0x1e,0x8a,0xc2,0xcb,0xf4,0x31,0x1e,0x8c,0xf5,0x9b,0x90,0x64,0xc5,0x02,0x02,0xb3,0x54,0x9d,0x38,0x44,0x78,0x45,0x42,0xa2,0x1f,0x22,0x06,0x87,0xba,0xef,0x44,0x7c,0x50,0xca,0xd5,0x08,0x8d,0xa0,0xf6,0x31,0xda,0x12,0xd5,0x0f,0xe3,0xd3,0x38,0x34,0x99,0x3a,0x46,0xe5,0xe8,0xa5,0x80,0x1c,0x0e,0xd6,0xd3,0x63,0x2b,0x62,0xf7,0x99,0x57,0xba,0xa8,0x2f,0x6f,0x84,0x96,0xbd,0xfe,0x3b,0x47,0x68,0x87,0x33,0x57,0x41,0x98,0xfd,0xde,0xe5,0x72,0xa0,0x2c,0xc2,0x00,0x87,0x5f,0x97,0xd9,0xe6,0xdf,0xe4,0x33,0x33,0xe0,0x4f,0x51,0x16,0xd1,0xd1,0x55,0xe2,0xa5,0x97,0x8a,0x5e,0x60,0x13,0x73,0xae,0x73,0x05,0x7b,0x7c,0x95,0x0c,0xff,0x27,0x6d,0x43,0xb1,0x3a,0x5c,0xa6,0x0c,0x01,0x72,0x7f,0x81,0xb0,0xa1,0x99,0x9c,0x9c,0xeb,0x7e,0x48,0xe1,0x09,0x18,0x61,0x45,0xfc,0xb1,0xb2,0x33,0x82,0x26,0xcc,0x42,0xfe,0x8a,0x54,0x35,0xf8,0x4c,0x9a,0x68,0x8d,0x67,0xc5,0xb3,0x36,0x83,0x9d,0x5a,0x11,0x11,0x81,0xcc,0xe5,0xb8,0xa5,0xb4,0xef,0x02,0x03,0x01,0x00,0x01,0x02,0x82,0x01,0x01,0x00,0xbd,0x97,0x63,0xf5,0x50,0xf8,0x75,0xf7,0x6a,0x9b,0x07,0xf2,0x55,0xb3,0x68,0xfe,0x4a,0x75,0xc6,0x66,0xe8,0x5e,0x17,0x5f,0xc7,0x5a,0x68,0x95,0x16,0xfc,0xcd,0x98,0xd9,0x26,0x39,0xec,0x4a,0xb4,0x99,0x24,0xfe,0x7c,0xa6,0x4e,0xba,0xf6,0xeb,0xb0,0x97,0x4f,0xd0,0xd3,0xab,0x16,0xfc,0x93,0xe5,0x99,0x71,0x8f,0x39,0xf9,0x9d,0xcc,0xfe,0xa9,0x61,0x1d,0xa0,0x6e,0xdb,0x60,0xbd,0x09,0x87,0xb6,0xc1,0xfc,0x1a,0xb9,0x1d,0xdb,0x0d,0xad,0xcd,0x1e,0x39,0xd3,0x8c,0x9d,0xd3,0xda,0x43,0x13,0xfd,0x4d,0x91,0x6a,0x83,0xcd,0xdc,0x86,0x1e,0xeb,0xfb,0x9f,0xfb,0x6a,0xa5,0x82,0x94,0x2a,0xb8,0xb4,0xf4,0x25,0xdd,0x9b,0x2e,0x57,0xfd,0x80,0x6c,0x9e,0x35,0x05,0x01,0x64,0xdb,0x3c,0xd4,0x34,0xfc,0x41,0xe0,0x94,0xd1,0x50,0xa2,0x91,0x2c,0x83,0x0e,0x72,0xab,0xe2,0xe9,0x07,0x14,0x37,0xdb,0x86,0x6f,0x41,0x26,0x35,0xbd,0xcd,0x39,0x98,0x42,0xea,0x50,0x26,0x00,0xf5,0x6a,0x24,0x89,0x6f,0x17,0x78,0xdc,0x19,0x97,0xb0,0x0a,0x37,0x84,0x1e,0xf4,0xc5,0x47,0x79,0xcd,0xea,0x0e,0x0e,0x47,0xfd,0x96,0x46,0x69,0x9b,0x90,0xb1,0xe2,0x72,0x13,0x46,0xa3,0xf9,0x57,0xd6,0x6a,0xa7,0xf4,0xd3,0xf8,0xf4,0x05,0x0f,0x30,0xe7,0x2f,0x29,0xd9,0xfd,0xed,0xb0,0xc5,0xeb,0x30,0xa4,0xf1,0x25,0x9b,0xdb,0x2d,0x67,0x93,0x19,0xc4,0xca,0x84,0xc4,0xc3,0x64,0xa8,0xff,0xa4,0xd5,0xd1,0xb0,0x69,0xbd,0xcb,0x76,0x4d,0xcf,0xd0,0xc1,0x56,0x4e,0x5c,0xd9,0x02,0x81,0x81,0x00,0xfc,0x7f,0x13,0x79,0xef,0x87,0x60,0xd8,0x17,0xbc,0x15,0x04,0x75,0xac,0xdd,0xf2,0xa0,0xcb,0x90,0x83,0x7a,0x4d,0x65,0x39,0x28,0x9a,0xb7,0x52,0x6b,0x11,0x7f,0xcc,0xc7,0x28,0x0c,0xc2,0xc6,0xce,0x58,0x02,0xe4,0x1b,0x13,0x97,0xe7,0xdc,0x7b,0x33,0xe7,0x20,0x9c,0x36,0x53,0xfa,0x79,0x20,0xfe,0x70,0x29,0x3e,0x71,0xc0,0xf0,0x2a,0xe5,0x7c,0xcb,0xac,0x98,0x32,0xb4,0xcf,0x53,0x94,0xbd,0xc9,0x73,0xb6,0x9a,0x76,0xb1,0x1f,0x2b,0x27,0x0e,0xef,0xbc,0x3c,0xc9,0x6c,0x63,0x2b,0x5c,0x31,0xbf,0x25,0x17,0xaa,0x0c,0x25,0xad,0xdb,0xf3,0xfd,0x65,0x14,0x0c,0xd8,0xc2,0x69,0xd3,0x9f,0xa7,0x63,0x0e,0x26,0x58,0x63,0xb1,0xe8,0x7b,0x80,0x27,0x45,0xbd,0xc6,0xd2,0x25,0x02,0x81,0x81,0x00,0xca,0x4a,0x73,0x28,0x2a,0x0a,0xec,0xc4,0xbd,0x9d,0x4e,0x08,0x63,0x41,0xa5,0x7b,0x53,0x8b,0x99,0xf5,0x57,0x45,0x50,0xad,0xf9,0xc7,0x5f,0xd5,0xf1,0x24,0x89,0x22,0x92,0x5e,0xa3,0xf0,0x27,0x35,0x69,0x5c,0x90,0x69,0x17,0x44,0x0a,0x84,0xe7,0x28,0xee,0x84,0x02,0x4c,0x7e,0x2e,0xb0,0x95,0xc9,0xae,0x25,0xa8,0x2d,0x8a,0x37,0xca,0xf7,0xd4,0x0f,0x91,0xd5,0x39,0xcd,0xe9,0x25,0xe8,0xcc,0x57,0x87,0xcb,0xab,0x00,0x4d,0xe6,0xe0,0x72,0x18,0x1b,0x15,0x73,0xdf,0x41,0xc2,0x25,0xd2,0xdc,0x68,0x7d,0xdb,0x07,0x8f,0xd1,0x47,0x9a,0x17,0x3b,0x5a,0xd8,0x96,0x35,0xd7,0x18,0xd2,0xe6,0xe1,0x01,0xb8,0xe9,0xca,0xf3,0x0f,0xb0,0x48,0x45,0x4e,0xf2,0xb6,0xb1,0xbc,0x83,0x02,0x81,0x81,0x00,0xc5,0xf4,0x0a,0x9c,0xea,0x41,0x44,0x97,0xa5,0xe3,0xfa,0xc6,0x48,0x4b,0x82,0xa6,0x19,0x91,0xfe,0x76,0x55,0x88,0x1f,0xf7,0xb3,0xf1,0xb8,0x0f,0x91,0x89,0x62,0x9c,0x74,0xf6,0xdd,0x2a,0x47,0x1a,0xb6,0xbd,0x6d,0x80,0x1c,0xd8,0x57,0x1a,0xf0,0x2c,0x3c,0xe3,0xc0,0x14,0x87,0xba,0x33,0x04,0xbe,0xf5,0xc8,0x20,0x00,0xa6,0xb6,0xa3,0xaa,0xcf,0x30,0x0e,0xdc,0x33,0xc4,0xb5,0x56,0x5d,0xa2,0x7d,0x31,0x8e,0xd3,0x82,0x82,0x52,0x61,0x4e,0x79,0xd3,0x51,0xcc,0x86,0x4d,0xc7,0x61,0xd3,0x21,0xdd,0x2d,0x83,0x63,0xf9,0xaa,0x00,0xa8,0x14,0x9d,0x70,0x85,0x4b,0x9d,0x14,0xae,0x4b,0x0f,0x3b,0xf7,0xd8,0xbc,0x0f,0x47,0xf9,0xce,0xbe,0x24,0x36,0xa5,0xe2,0xa6,0xe1,0x51,0x02,0x81,0x81,0x00,0xa9,0xd3,0x44,0xc8,0x04,0x3b,0xb5,0xb8,0x19,0x63,0x75,0x3e,0x2f,0x6d,0xce,0x2a,0x31,0xe2,0x31,0xf7,0x39,0x33,0xd4,0xde,0xa9,0xa2,0x4a,0x7f,0x86,0x79,0x60,0xb3,0x68,0x64,0x11,0x87,0x2c,0xb3,0x77,0x67,0xa1,0x48,0xc8,0xa2,0x73,0x9e,0x4d,0x9e,0x1c,0x57,0x30,0xc2,0xdc,0xef,0xff,0x89,0x50,0x8e,0x65,0xc8,0xc1,0xaa,0x96,0xda,0x4b,0xa2,0x79,0x0b,0xba,0x11,0x54,0x1f,0x96,0x96,0xd0,0xed,0xee,0xef,0xf9,0xf8,0x40,0x6e,0x42,0x21,0x26,0xc1,0x9e,0x09,0xef,0xf4,0xf9,0xb3,0xdd,0x48,0xf2,0x64,0x2e,0x3c,0x33,0xed,0xc3,0x09,0xc6,0xd5,0x2a,0x98,0x47,0xca,0x9d,0x70,0x96,0xa6,0x03,0x61,0xf9,0xc6,0x34,0x7e,0x47,0xbe,0x7b,0x7d,0xcc,0x20,0x91,0x65,0xb7,0x57,0x02,0x81,0x80,0x45,0x80,0x1b,0xa3,0x69,0x88,0x96,0x4e,0xf3,0x98,0x2e,0xb5,0x81,0x9d,0x5d,0x56,0xb8,0x47,0xe3,0xc6,0x63,0xb8,0x0b,0xb3,0x1b,0xd2,0x96,0xde,0x28,0x95,0xf5,0x85,0x11,0x01,0x39,0x64,0x73,0xfa,0x1f,0x1e,0x39,0x00,0x0c,0x11,0x0d,0x34,0x3a,0xe6,0xaa,0xf6,0x05,0xbf,0xe5,0x6a,0x17,0x2d,0xd3,0xfa,0x46,0xb1,0xe5,0x96,0x22,0x8c,0x63,0x35,0x1b,0xd5,0x7a,0xbf,0x21,0xff,0x7d,0xa0,0x6f,0x93,0xb2,0x0f,0x47,0xc8,0x4f,0x10,0x7f,0x66,0xb8,0xc9,0xe4,0xc9,0x60,0x81,0xce,0x26,0xeb,0x40,0xe3,0x1e,0x96,0xbd,0xdb,0x97,0x15,0xeb,0xa2,0x3e,0xef,0x8b,0xd5,0x85,0x89,0xb8,0x2b,0x62,0xc2,0x9b,0x80,0x58,0x66,0xbe,0xdb,0x54,0x3b,0xb4,0xf7,0xbf,0x3f,0x8e,0xc9,0x8a };
        prikey.setPrivateKey(bin_prikey, sizeof(bin_prikey));
        pubkey.setPublicKey(bin_pubkey, sizeof(bin_pubkey));

        std::unique_ptr<Result<Buffer>> result_with_buffer;
        std::unique_ptr<Result<void>> result;

        result = cipher->init(Cipher::ENCRYPT_MODE, &pubkey);
        result_with_buffer = cipher->update("abcd", 4);
        printHexBytes(&result_with_buffer->result().data()[0], result_with_buffer->result().size());
        result_with_buffer = cipher->doFinal();
        printHexBytes(&result_with_buffer->result().data()[0], result_with_buffer->result().size());
    }

    // ECDH Test
    if (0)
    {
        uint8_t a_pubkey[] = { 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x59, 0x8d, 0x70, 0xf6, 0x7f, 0x93, 0x87, 0xbb, 0x13, 0x08, 0xc7, 0xa3, 0xc4, 0xf8, 0x87, 0x57, 0xdb, 0xe0, 0x0e, 0xc1, 0x64, 0x8b, 0xfc, 0x1f, 0x5f, 0x5f, 0x05, 0xba, 0xce, 0xfa, 0xde, 0xf8, 0xb4, 0x42, 0xb8, 0xf5, 0x49, 0xde, 0xb5, 0x10, 0x14, 0x63, 0x40, 0xec, 0xd6, 0x6c, 0xf0, 0x5d, 0x11, 0x8d, 0x21, 0xe5, 0x99, 0x6a, 0x48, 0xff, 0x3c, 0x91, 0xc4, 0x27, 0xd2, 0x33, 0x08, 0x15 };
        uint8_t a_prikey[] = { 0x30, 0x41, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x27, 0x30, 0x25, 0x02, 0x01, 0x01, 0x04, 0x20, 0x5d, 0x58, 0x4e, 0xfc, 0x9e, 0x75, 0x7f, 0x2b, 0x69, 0xf7, 0x09, 0x19, 0x68, 0x26, 0x00, 0x77, 0xa7, 0x35, 0x6e, 0x0c, 0x74, 0x00, 0xbe, 0x89, 0xd4, 0xf9, 0x53, 0x31, 0x55, 0x9d, 0x94, 0xbf };
        uint8_t b_pubkey[] = { 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x12, 0x22, 0x31, 0x9c, 0xb1, 0x5e, 0xbd, 0xb7, 0xdd, 0x7e, 0xad, 0x20, 0x71, 0x8f, 0xd4, 0xf3, 0x57, 0x02, 0x95, 0xf3, 0xb4, 0xc4, 0xbd, 0xf8, 0x04, 0x42, 0xed, 0x4b, 0xc0, 0x4f, 0x8d, 0x36, 0x15, 0xc4, 0x1c, 0x03, 0xd1, 0xf0, 0xcf, 0x4f, 0xf0, 0xc1, 0x60, 0xaa, 0x4c, 0x23, 0x03, 0x71, 0x40, 0xaa, 0xb5, 0xcb, 0x28, 0x6b, 0xf9, 0x56, 0x57, 0xfd, 0xb4, 0xa7, 0x3b, 0x78, 0x57, 0xeb };
        uint8_t b_prikey[] = { 0x30, 0x41, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x27, 0x30, 0x25, 0x02, 0x01, 0x01, 0x04, 0x20, 0xb3, 0x5b, 0x9e, 0xfb, 0x80, 0x04, 0x53, 0x47, 0x3f, 0x5e, 0xbb, 0x88, 0x06, 0x89, 0x38, 0x18, 0x07, 0x9a, 0x57, 0x01, 0x89, 0x9b, 0x8d, 0xde, 0xb7, 0xd6, 0x81, 0x2a, 0x93, 0x10, 0x7f, 0x37 };
        uint8_t secret_answer[] = { 0xcb, 0x3b, 0x7e, 0x9d, 0x27, 0xf5, 0xd4, 0x77, 0xa8, 0x9a, 0xe8, 0xb4, 0xfa, 0x19, 0x59, 0x00, 0x71, 0x33, 0x20, 0x5a, 0x15, 0xe5, 0xfc, 0x5a, 0x2a, 0x5b, 0x78, 0xf1, 0xa4, 0x4e, 0x6b, 0x1e };

        jcp::AsymKeyImpl apri; apri.setPrivateKey(a_prikey, sizeof(a_prikey));
        jcp::AsymKeyImpl bpub; bpub.setPublicKey(b_pubkey, sizeof(b_pubkey));

        std::unique_ptr<KeyAgreement> ka(KeyAgreement::getInstance("ECDH"));
        ka->init(&apri);
        ka->doPhase(&bpub);
        std::unique_ptr<Result<Buffer>> secret = ka->generateSecret();
        printHexBytes(&secret->result().data()[0], secret->result().size());

        // TEST OK
    }

    // ECDSA Test
    if (0)
    {
        uint8_t a_pubkey[] = { 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x59, 0x8d, 0x70, 0xf6, 0x7f, 0x93, 0x87, 0xbb, 0x13, 0x08, 0xc7, 0xa3, 0xc4, 0xf8, 0x87, 0x57, 0xdb, 0xe0, 0x0e, 0xc1, 0x64, 0x8b, 0xfc, 0x1f, 0x5f, 0x5f, 0x05, 0xba, 0xce, 0xfa, 0xde, 0xf8, 0xb4, 0x42, 0xb8, 0xf5, 0x49, 0xde, 0xb5, 0x10, 0x14, 0x63, 0x40, 0xec, 0xd6, 0x6c, 0xf0, 0x5d, 0x11, 0x8d, 0x21, 0xe5, 0x99, 0x6a, 0x48, 0xff, 0x3c, 0x91, 0xc4, 0x27, 0xd2, 0x33, 0x08, 0x15 };
        uint8_t a_prikey[] = { 0x30, 0x41, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x27, 0x30, 0x25, 0x02, 0x01, 0x01, 0x04, 0x20, 0x5d, 0x58, 0x4e, 0xfc, 0x9e, 0x75, 0x7f, 0x2b, 0x69, 0xf7, 0x09, 0x19, 0x68, 0x26, 0x00, 0x77, 0xa7, 0x35, 0x6e, 0x0c, 0x74, 0x00, 0xbe, 0x89, 0xd4, 0xf9, 0x53, 0x31, 0x55, 0x9d, 0x94, 0xbf };
        uint8_t secret_answer[] = { 0xcb, 0x3b, 0x7e, 0x9d, 0x27, 0xf5, 0xd4, 0x77, 0xa8, 0x9a, 0xe8, 0xb4, 0xfa, 0x19, 0x59, 0x00, 0x71, 0x33, 0x20, 0x5a, 0x15, 0xe5, 0xfc, 0x5a, 0x2a, 0x5b, 0x78, 0xf1, 0xa4, 0x4e, 0x6b, 0x1e };

        jcp::AsymKeyImpl apri; apri.setPrivateKey(a_prikey, sizeof(a_prikey));
        jcp::AsymKeyImpl apub; apub.setPublicKey(a_pubkey, sizeof(a_pubkey));

        std::unique_ptr<Signature> sign(Signature::getInstance("SHA256withECDSA"));
        sign->initSign(&apri);
        sign->update("12345678", 8);
        std::unique_ptr<Result<Buffer>> signature_result = sign->sign();
        printHexBytes(&signature_result->result().data()[0], signature_result->result().size());

        std::unique_ptr<Signature> verify(Signature::getInstance("SHA256withECDSA"));
        verify->initVerify(&apub);
        verify->update("12345678", 8);
        std::unique_ptr<Result<bool>> verify_result = verify->verify(signature_result->result().data(), signature_result->result().size());
        printf("\nverify = %d\n", verify_result->result());

        // TEST OK
    }

    // PBKDF2 Test
    if (0) {
        unsigned char salt[] = "SALT1234";

        const jcp::SecretKeyFactory* factory = jcp::SecretKeyFactory::getInstance("PBKDF2WithHmacSHA1");
        jcp::PBEKeySpec keySpec("PASSWORD", 8, salt, 8, 1000, 128);
        std::unique_ptr<Result<SecretKey>> result = factory->generateSecret(&keySpec);
        std::cout << "ENCODED : " << std::endl;
        printHexBytes(result->result().getEncoded().data(), result->result().getEncoded().size());
        // 77 27 25 72 63 fe 4f a3 77 38 be 1b 3b 04 42 ab
        // TEST OK
    }

    return 0;
}

Comment +0

(설명 추가중... github에 써야하는데...)

 

AsymSecureFile은 Asymmetric기반 암호화를 이용하여 데이터 Sign/Encrypt를 구현하는 Java 라이브러리 입니다.

(추후 C++도 지원예정)

 

OperationType으로써 SIGN과 PUBLIC_ENCRYPT를 지원하며 RSA키와 EC키를 지원하고, Java에서는 PKCS11도 지원하여 HSM과 연동 가능합니다.

 

SIGN은 PrivateKey로 데이터를 서명하며 이를 통해 데이터를 조작불가하게 전달하고 보관할 수 있습니다. 라이센스 검증 등에 유용하게 사용할 수 있습니다.

 

PUBLIC_ENCRYPT는 PublicKey로 데이터를 암호화하여 데이터를 안전하게 전달하고 PrivateKey를 가진 자만 해당 데이터를 읽을 수 있습니다.

 

AuthKey를 적용하여 데이터 암호화도 함께 작동합니다.

 

UserChunk라는 것은 사용자 정의 데이터를 추가할 수 있습니다. 해당 데이터는 기본적으로 암호화하지 않고 Read하는 쪽에서 AsymKey를 설정하지 않은 상태에서도 읽을 수 있습니다.

비 암호화 / AuthKey로 암호화 옵션을 가지고 있으며, AuthKey로 암호화할 시 UserChunk를 보다 안전하게 전달 할 수 있습니다.

 

 

 

jcenter() repository에서 'kr.jclab.javautils:asymsecurefile:1.0.20' 으로 사용하실 수 있습니다.

(1.0.20 버전이후 최신걸 사용해 주세요~)

 

전에 만들었던 signedsecurefile도 하위 호환성을 위해 지원합니다. (읽기만)

 

https://github.com/jc-lab/javautils-asymsecurefile

 

jc-lab/javautils-asymsecurefile

Contribute to jc-lab/javautils-asymsecurefile development by creating an account on GitHub.

github.com

https://bintray.com/jc-lab/java-utils/asymsecurefile

 

Package asymsecurefile - jc-lab

 

bintray.com

 

테스트코드 : 

import kr.jclab.javautils.asymsecurefile.*;
import kr.jclab.javautils.signedsecurefile.InvalidKeyException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.pkcs11.SunPKCS11;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.Enumeration;

public class TestMain {
    public static String bytesToHex(byte[] bytes) {
        final char hexArray[] = "0123456789abcdef".toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            if(stringBuilder.length() > 0)
                stringBuilder.append(",");
            stringBuilder.append("0x");
            stringBuilder.append(hexArray[v >>> 4]);
            stringBuilder.append(hexArray[v & 0xf]);
        }
        return stringBuilder.toString();
    }

    public static void pkcs11Test() throws Exception {
        Security.insertProviderAt(new BouncyCastleProvider(), 1);
        SunPKCS11 securityProvider = new SunPKCS11("D:\\SoftHSM2\\java-softhsm.cfg");
        KeyStore keyStore = KeyStore.getInstance("PKCS11", securityProvider);
        keyStore.load(null, "123456".toCharArray());

        Certificate certificate = keyStore.getCertificate("test-1");
        Key key = keyStore.getKey("test-1", null);


        // RSA Test
        //KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(AsymAlgorithm.RSA.getAlgorithm(), securityProvider);
        //KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(AsymAlgorithm.RSA.getAlgorithm());
        //keyPairGenerator.initialize(1024);

        // EC Test
        //KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(AsymAlgorithm.EC.getAlgorithm(), securityProvider);
        //KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(AsymAlgorithm.EC.getAlgorithm());
        //keyPairGenerator.initialize(256);

        //KeyPair keyPair = keyPairGenerator.generateKeyPair();
        KeyPair keyPair = new KeyPair(certificate.getPublicKey(), (PrivateKey)key);

        //Key storedKey = keyStore.getKey("test-ec-1", null);


        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        /*
        // SignedSecureFileOutputStream test
        try(SignedSecureFileOutputStream outputStream = new SignedSecureFileOutputStream(bos, keyPair.getPrivate(), "TEST")) {
            for (int i = 0; i < 10000; i++) {
                byte[] buf = new byte[] {10};
                outputStream.write(buf);
            }
            outputStream.save();
        }
        */

        // AsymSecureFileOutputStream test
        try(AsymSecureFileOutputStream outputStream = new AsymSecureFileOutputStream(OperationType.PUBLIC_ENCRYPT, bos, securityProvider)) {
            outputStream.setAsymKey(keyPair);
            outputStream.setAuthKey("TEST".getBytes());

            outputStream.setUserChunk(
                    UserChunk.builder()
                            .withUserCode((short)1)
                            .withFlag(Chunk.Flag.EncryptedWithAuthEncKey)
                            .withData(new byte[] {0x10, 0x20, 0x30, 0x40, 0x50,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2})
                            .build());

            for (int i = 0; i < 5766; i++) {
                outputStream.write(10);
            }

            outputStream.finish();
        }

        byte[] payload = bos.toByteArray();
        try(AsymSecureFileInputStream inputStream = new AsymSecureFileInputStream(new ByteArrayInputStream(payload), securityProvider))
        {
            while(inputStream.headerRead() == 1)
            {
                System.out.println("continous head reading");
            }

            inputStream.setAuthKey("TEST".getBytes());
            inputStream.setAsymKey(keyPair);

            Enumeration<UserChunk> enumeration = inputStream.userChunks();
            while (enumeration.hasMoreElements()) {
                UserChunk userChunk = enumeration.nextElement();
                System.out.println("userChunk : " + userChunk + " / " + userChunk.getDataSize() + " / " + bytesToHex(userChunk.getData()));
            }

            int readlen;
            byte[] buffer = new byte[8192];
            while((readlen = inputStream.read(buffer)) > 0) {
                System.out.println("READLEN : " + readlen + " // " + bytesToHex(Arrays.copyOf(buffer, readlen)));
            }

        }

        System.out.println("PAYLOAD : " + bytesToHex(payload));

        securityProvider.logout();
    }

    public static void normalTest() throws Exception {
        Provider securityProvider = new BouncyCastleProvider();

        // RSA Test
        //KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(AsymAlgorithm.RSA.getAlgorithm(), securityProvider);
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(AsymAlgorithm.RSA.getAlgorithm());
        keyPairGenerator.initialize(1024);

        // EC Test
        //KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(AsymAlgorithm.EC.getAlgorithm(), securityProvider);
        //KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(AsymAlgorithm.EC.getAlgorithm());
        //keyPairGenerator.initialize(256);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        //Key storedKey = keyStore.getKey("test-ec-1", null);


        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        /*
        // SignedSecureFileOutputStream test
        try(SignedSecureFileOutputStream outputStream = new SignedSecureFileOutputStream(bos, keyPair.getPrivate(), "TEST")) {
            for (int i = 0; i < 10000; i++) {
                byte[] buf = new byte[] {10};
                outputStream.write(buf);
            }
            outputStream.save();
        }
        */

        // AsymSecureFileOutputStream test
        try(AsymSecureFileOutputStream outputStream = new AsymSecureFileOutputStream(OperationType.SIGN, bos, securityProvider)) {
            outputStream.setAsymKey(keyPair);
            outputStream.setAuthKey("TEST".getBytes());

            outputStream.setUserChunk(
                    UserChunk.builder()
                            .withFlag(Chunk.Flag.EncryptedWithAuthEncKey)
                            .withData(new byte[] {0x10, 0x20, 0x30, 0x40, 0x50})
                            .build());

            for (int i = 0; i < 10000; i++) {
                outputStream.write(10);
            }

            outputStream.finish();
        }

        byte[] payload = bos.toByteArray();
        try(AsymSecureFileInputStream inputStream = new AsymSecureFileInputStream(new ByteArrayInputStream(payload), securityProvider))
        {
            while(inputStream.headerRead() == 1)
            {
                System.out.println("continous head reading");
            }

            inputStream.setAuthKey("TEST".getBytes());
            inputStream.setAsymKey(keyPair);

            Enumeration<UserChunk> enumeration = inputStream.userChunks();
            while (enumeration.hasMoreElements()) {
                UserChunk userChunk = enumeration.nextElement();
                System.out.println("userChunk : " + userChunk + " / " + userChunk.getDataSize() + " / " + bytesToHex(userChunk.getData()));
            }

            int readlen;
            byte[] buffer = new byte[8192];
            while((readlen = inputStream.read(buffer)) > 0) {
                System.out.println("READLEN : " + readlen + " // " + bytesToHex(Arrays.copyOf(buffer, readlen)));
            }

        }

        System.out.println("PublicKey : " + bytesToHex(keyPair.getPublic().getEncoded()));

        System.out.println("PrivateKey : " + bytesToHex(keyPair.getPrivate().getEncoded()));

        System.out.println("PAYLOAD : " + bytesToHex(payload));
    }

    public static void keyGen() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
        KeyPair keyPairA = keyPairGenerator.generateKeyPair();
        KeyPair keyPairB = keyPairGenerator.generateKeyPair();

        System.out.println("A PUBLIC : " + bytesToHex(keyPairA.getPublic().getEncoded()));
        System.out.println("A PRIVATE : " + bytesToHex(keyPairA.getPrivate().getEncoded()));

        System.out.println("B PUBLIC : " + bytesToHex(keyPairB.getPublic().getEncoded()));
        System.out.println("B PRIVATE : " + bytesToHex(keyPairB.getPrivate().getEncoded()));

        KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
        keyAgreement.init(keyPairA.getPrivate());
        Key key = keyAgreement.doPhase(keyPairB.getPublic(), true);
        //System.out.println("ENCODED : " + bytesToHex(key.getEncoded()));

        System.out.println("SECRET : " + bytesToHex(keyAgreement.generateSecret()));
    }

    public static void main(String[] args) throws Exception {
        //pkcs11Test();
        normalTest();
        //keyGen();
    }
}

Comment +0

https://github.com/jc-lab/libstomp-cpp

 

jc-lab/libstomp-cpp

Contribute to jc-lab/libstomp-cpp development by creating an account on GitHub.

github.com

 

libstomp-cpp는 C++11를 이용한 stomp websocket protocol 구현 소스입니다.

Apache License 2.0을 따름으로 해당 라이센스 하에 자유롭게 사용 가능합니다.

자세한 기능에 대한 사항은 github를 참고해 주시기 바랍니다.

 

(작성중..)

 

Comment +0

https://github.com/jc-lab/sqlcipher

Comment +0

JsCPPBean는 C++에서 Bean과 Autowired를 구현해주는 라이브러리 입니다.

전역 프로그램에서 사용되는 클래스를 일일히 선언하고 공통 헤더파일을 가져오고.. 또 공통헤더가 바뀌면 컴파일 엄청 오래 걸리고.. 하는 문제를 해결할 수 있으며 Java스러운 코딩이 가능합니다.

JsCPPBean 라이브러리 : https://github.com/jc-lab/JsCPPBean
테스트 코드 솔루션(VS) : https://github.com/jc-lab/JsCPPBeanTest

예제(일부)

#include "MainProcess.h"

#include <stdio.h>

JSCPPBEAN_BEAN_BEGIN(MainProcess)
JSCPPBEAN_BEAN_AUTOWIRED(MainProcess, ChildService, m_child)
JSCPPBEAN_BEAN_AUTOWIRED(MainProcess, ParentService, m_parent)
JSCPPBEAN_BEAN_END()

class TestClass {
public:
    int b;
};

void MainProcess::run()
{
    printf("[MainProcess] TestClass : %s / %d\n", typeid(TestClass).name(), typeid(TestClass).hash_code());

    printf("ChildProcess[MainProcess] : %s\n", typeid(ChildService).raw_name());
    printf("ChildProcess[MainProcess] : %s\n", typeid(ChildService).name());
    printf("ChildProcess[MainProcess] : %d\n", typeid(ChildService).hash_code());

    printf("MainProcess::run\n");
}

Comment +0

라이브러리 소스 : https://github.com/jc-lab/JsBsonRPCSerializable

테스트 VS프로젝트 : https://github.com/jc-lab/JsBsonRPCSerializable-testproject

JsBsonRPCSerializable는 C++ 에서 객체를 Serialize/Deserialze 할 수 있게 도와주는 라이브러리 입니다.

Serialize 형식은 Bson 형식을 따르며, JSONObjectMapper 클래스를 통해 json(rapidjson)변환 기능도 지원합니다.

테스트 소스

#include <stdio.h>

#include <string>
#include <map>
#include <list>
#include <vector>

#include "JsBsonRPCSerializable/Serializable.h"
#include "JsBsonRPCSerializable/plugins/JSONObjectMapper.h"

void dump(std::vector<unsigned char> &buffer)
{
    size_t i = 0;
    size_t len = buffer.size();
    for (i = 0; i < len; i++)
    {
        printf("%02x ", buffer[i]);
    }
    printf("\n");
}

class TestSubClassB : public JsBsonRPC::Serializable
{
public:
    JsBsonRPC::SType<int32_t> a;
    JsBsonRPC::SType<std::string> b;

    TestSubClassB() : Serializable("test2", 101)
    {
        this->serializableMapMember("a", a);
        this->serializableMapMember("b", b);
    }
};

class TestClassA : public JsBsonRPC::Serializable
{
public:
    JsBsonRPC::SType<int32_t> a;
    JsBsonRPC::SType<int64_t> b;
    JsBsonRPC::SType<double> d;
    JsBsonRPC::SType<std::string> e;
    JsBsonRPC::SType<std::vector<char> > xa; // binary
    JsBsonRPC::SType<std::list<std::string> > xb;
    JsBsonRPC::SType<std::list< std::vector<char> > > xc;
    JsBsonRPC::SType<double> xd;
    JsBsonRPC::SType<std::map<std::string, std::string> > xf;

    JsBsonRPC::SType<TestSubClassB> sub;
    JsBsonRPC::SType<std::map<std::string, TestSubClassB> > submap;

    TestClassA() : Serializable("test", 101)
    {
        this->serializableMapMember("a", a);
        this->serializableMapMember("b", b);
        this->serializableMapMember("d", d);
        this->serializableMapMember("e", e);
        this->serializableMapMember("xa", xa);
        this->serializableMapMember("xb", xb);
        this->serializableMapMember("xc", xc);
        this->serializableMapMember("xd", xd);
        this->serializableMapMember("xf", xf);
        this->serializableMapMember("sub", sub);
        this->serializableMapMember("submap", submap);
    }
};

int main()
{
    std::vector<unsigned char> payload;

    std::vector<char> test;

    TestClassA testA;
    TestClassA testB;
    TestClassA testC;

    testA.a.set(0xff);
    testA.b.set(0x1000000000000002);
    testA.d.set(3.14);
    testA.e.set("aaaa");
    testA.xd.set(1.1);

    testA.xa.ref().push_back('1');
    testA.xa.ref().push_back('2');
    testA.xa.ref().push_back('3');
    testA.xa.ref().push_back('4');
    testA.xb.ref().push_back("hello");
    testA.xb.ref().push_back("world");

    test.clear();
    test.push_back('1');
    test.push_back('1');
    test.push_back('1');
    testA.xc.ref().push_back(test);
    test.clear();
    test.push_back('2');
    test.push_back('2');
    test.push_back('2');
    testA.xc.ref().push_back(test);

    testA.xf.ref()["aaaa"] = "aaaa";
    testA.xf.ref()["bbbb"] = "bbbb";
    testA.xf.ref()["cccc"] = "c";
    testA.xf.ref()["ee"] = "ad";
    testA.xf.ref()["dd"] = "aae";

    testA.sub.ref().a.set(10);
    testA.sub.ref().b.set("SUB TEXT!");

    testA.submap.ref()["a"].a.set(10);
    testA.submap.ref()["a"].b.set("20");

    testA.submap.ref()["b"].a.set(10);
    testA.submap.ref()["b"].b.set("40");

    payload.clear();
    testA.serialize(payload);
    dump(payload);

    testB.deserialize(payload);

    JsBsonRPC::JSONObjectMapper objectMapper;
    std::string jsondata = objectMapper.serialize(&testA);

    objectMapper.deserialize(&testC, jsondata);

    printf("JSON : %s\n", jsondata.c_str());

    return 0;
}

출력결과

34 01 00 00 10 61 00 ff 00 00 00 12 62 00 02 00 00 00 00 00 00 10 01 64 00 1f 85 eb 51 b8 1e 09 40 02 65 00 05 00 00 00 61 61 61 61 00 05 78 61 00 04 00 00 00 00 31 32 33 34 04 78 62 00 1f 00 00 00 02 30 00 06 00 00 00 68 65 6c 6c 6f 00 02 31 00 06 00 00 00 77 6f 72 6c 64 00 00 04 78 63 00 1b 00 00 00 05 30 00 03 00 00 00 00 31 31 31 05 31 00 03 00 00 00 00 32 32 32 00 01 78 64 00 9a 99 99 99 99 99 f1 3f 03 78 66 00 46 00 00 00 02 61 61 61 61 00 05 00 00 00 61 61 61 61 00 02 62 62 62 62 00 05 00 00 00 62 62 62 62 00 02 63 63 63 63 00 02 00 00 00 63 00 02 64 64 00 04 00 00 00 61 61 65 00 02 65 65 00 03 00 00 00 61 64 00 00 03 73 75 62 00 1d 00 00 00 10 61 00 0a 00 00 00 02 62 00 0a 00 00 00 53 55 42 20 54 45 58 54 21 00 00 03 73 75 62 6d 61 70 00 37 00 00 00 03 61 00 16 00 00 00 10 61 00 0a 00 00 00 02 62 00 03 00 00 00 32 30 00 00 03 62 00 16 00 00 00 10 61 00 0a 00 00 00 02 62 00 03 00 00 00 34 30 00 00 00 00
JSON : {"a":255,"b":1152921504606846978,"d":3.14,"e":"aaaa","xa":"MTIzNA==","xb":["hello","world"],"xc":["MTEx","MjIy"],"xd":1.1,"xf":{"aaaa":"aaaa","bbbb":"bbbb","cccc":"c","dd":"aae","ee":"ad"},"sub":{"a":10,"b":"SUB TEXT!"},"submap":{"a":{"a":10,"b":"20"},"b":{"a":10,"b":"40"}}}

Comment +0

spring-boot-rest-http-invoker

기존의 HttpInvoker는 객체를 Serialize할 때 JavaSerializer을 사용합니다.

고로 JAVA 9 이전에서는 서로 다른 버전의 JVM이거나 사소한 객체의 버전이 다른 경우 정상적으로 동작하지 않습니다.

spring-boot-rest-http-invoker는 JavaSerializer 대신에 Jackson ObjectMapper를 사용하여 Restful API로 변환합니다.

RemoteInvocation 형식을 맞춘다면 PHP나 다른 언어에서도 동일하게 접근할 수 있습니다.

프로토콜 형식에 대해서는 아래를 참고해 주세요.

github : https://github.com/jc-lab/spring-boot-rest-http-invoker

bintray : https://bintray.com/jc-lab/spring.boot/spring-boot-rest-http-invoker

Maven


<dependency>

  <groupId>kr.jclab.spring</groupId>

  <artifactId>spring-boot-rest-http-invoker</artifactId>

  <version>(bintray에서 최신버전 확인)</version>

  <type>pom</type>

</dependency>

Gradle


implementation 'kr.jclab.spring:spring-boot-rest-http-invoker:(bintray에서 최신버전 확인)'

예제 소스


import com.fasterxml.jackson.databind.ObjectMapper;

import com.zeronsoftn.demo.demo1rpc.controller.TestContoller;

import kr.jclab.spring.resthttpinvoker.RestHttpInvokerProxyFactoryBean;

import kr.jclab.spring.resthttpinvoker.RestHttpInvokerServiceExporter;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean;

import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;



@Configuration

public class RPCConfig {

    // Invoker 서버에서

    @Bean("/api/test")

    HttpInvokerServiceExporter apiExporter(TestService testService) {

        ObjectMapper objectMapper = new ObjectMapper();

        objectMapper.registerSubtypes(TestContoller.Test.class);

        RestHttpInvokerServiceExporter exporter = new RestHttpInvokerServiceExporter();

        exporter.setObjectMapper(objectMapper);

        exporter.setService(testService);

        exporter.setServiceInterface(TestService.class);

        return exporter;

    }



    // Invoker Client에서

    @Bean

    HttpInvokerProxyFactoryBean testService() {

        ObjectMapper objectMapper = new ObjectMapper();

        objectMapper.registerSubtypes(TestContoller.Test.class);

        RestHttpInvokerProxyFactoryBean factoryBean = new RestHttpInvokerProxyFactoryBean();

        factoryBean.setObjectMapper(objectMapper);

        factoryBean.setServiceUrl("http://127.0.0.1:8080/api/test");

        factoryBean.setServiceInterface(TestService.class);

        return factoryBean;

    }



}


예제 Interface


public interface TestService {

    void test_1();

    void test_2(int a);

    void test_3(String b);

    void test_4(Map<String, String> c);

    int test_5(int a, int b);

}

void test1() 실행시


POST /api/test HTTP/1.1

Content-Type: application/json

Accept-Language: ko-KR

Accept-Encoding: gzip

User-Agent: Java/1.8.0_191

Host: 127.0.0.1:9999

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

Connection: keep-alive

Content-Length: 76



{"methodName":"test_1","parameterTypes":[],"arguments":[],"attributes":null}

HTTP/1.1 200 

Content-Type: application/json

Content-Length: 31

Date: Thu, 28 Feb 2019 01:27:24 GMT



{"value":null,"exception":null}

void test_2(10) 실행시


POST /api/test HTTP/1.1

Content-Type: application/json

Accept-Language: ko-KR

Accept-Encoding: gzip

User-Agent: Java/1.8.0_191

Host: 127.0.0.1:9999

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

Connection: keep-alive

Content-Length: 83



{"methodName":"test_2","parameterTypes":["int"],"arguments":[10],"attributes":null}

HTTP/1.1 200 

Content-Type: application/json

Content-Length: 31

Date: Thu, 28 Feb 2019 01:27:24 GMT



{"value":null,"exception":null}

void test_3("20") 실행시


POST /api/test HTTP/1.1

Content-Type: application/json

Accept-Language: ko-KR

Accept-Encoding: gzip

User-Agent: Java/1.8.0_191

Host: 127.0.0.1:9999

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

Connection: keep-alive

Content-Length: 98



{"methodName":"test_3","parameterTypes":["java.lang.String"],"arguments":["20"],"attributes":null}

HTTP/1.1 200 

Content-Type: application/json

Content-Length: 31

Date: Thu, 28 Feb 2019 01:27:24 GMT



{"value":null,"exception":null}

void test_4(Map<String, Object> map) 실행시


public static class Test {

        public int a;

        public int b;



        public Test() {}



        public Test(int a, int b) {

            this.a = a;

            this.b = b;

        }

    }



    @RequestMapping(path = "/test-1")

    @ResponseBody

    public String test1() {

        HashMap<String, Object> test = new HashMap<>();

        test.put("a", "aaaa");

        test.put("b", 123123);

        test.put("c", 3.14);

        test.put("d", new Test(10, 20));

        apiProxy.test_4(test);

        return "OK : " + apiProxy.test_5(22, 55);

    }

POST /api/test HTTP/1.1

Content-Type: application/json

Accept-Language: ko-KR

Accept-Encoding: gzip

User-Agent: Java/1.8.0_191

Host: 127.0.0.1:9999

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

Connection: keep-alive

Content-Length: 143



{"methodName":"test_4","parameterTypes":["java.util.Map"],"arguments":[{"a":"aaaa","b":123123,"c":3.14,"d":{"a":10,"b":20}}],"attributes":null}

HTTP/1.1 200 

Content-Type: application/json

Content-Length: 31

Date: Thu, 28 Feb 2019 01:47:29 GMT



{"value":null,"exception":null}

int test_5(22, 55) 실행시


POST /api/test HTTP/1.1

Content-Type: application/json

Accept-Language: ko-KR

Accept-Encoding: gzip

User-Agent: Java/1.8.0_191

Host: 127.0.0.1:9999

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

Connection: keep-alive

Content-Length: 92



{"methodName":"test_5","parameterTypes":["int","int"],"arguments":[22,55],"attributes":null}

HTTP/1.1 200 

Content-Type: application/json

Content-Length: 29

Date: Thu, 28 Feb 2019 01:47:29 GMT



{"value":77,"exception":null}

Comment +2

  • 2019.04.04 17:47

    비밀댓글입니다

    • 안녕하세요. 덧글이 늦어 죄송합니다^^
      일단 spring-boot-rest-http-invoker는 기존의 HttpInvoker는 객체를 Serialize할 때 JavaSerializer을 사용하기 때문에 JAVA 9 이전에서는 서로 다른 버전의 JVM이거나 사소한 객체의 버전이 다른 경우 정상적으로 동작하지 않는 문제를 해결하기 위하여, 또한 다른 언어와 API 호환을 위하여 만든 라이브러리 입니다.

      payload전달에 대해 JavaSerializer대신 json형식으로 전달하는 방식으로 인하여 발행하는 단점으로는 모든 Java개체를 Serialize할 수는 없다는 것이 단점이긴 합니다.
      예를들어 final 객체라든가 geter가 없는 private 필드가 존재하거나 @JsonCreator없이 NoArgsConstructor가 없는 클래스라든가 복잡한 객체(Type이 명시되지 않은 Object형 타입으로 선언되어있는 클래스 등)에 대해서는 Serialize가 불가하여 오류가 발생할 수 있습니다.
      따라서 이러한 객체를 사용하지 않도록 사용자가 Parmeter로 들어가는 클래스와 Return되는 Class, Throwable되는 Class에 대해 Jackson으로 Serialize/Deserialize될 수 있도록 만들어진 클래스를 사용해야 합니다.

MS3는 Mini Simple Storage Service의 약자로 만들어진 프로젝트 명으로써

Amazon S3 클라이언트와 호환되는! (라이브러리 자체가 호환됩니다!)

Object Storage 서버 및 클라이언트 입니다.


https://bintray.com/jc-lab/cloud/ms3-springserver

https://bintray.com/jc-lab/cloud/ms3-client


jcenter repository를 통해 사용하실 수 있습니다.


서버/클라이언트 함께 있는 예제소스입니다.

https://github.com/jc-lab/ms3-springserver-test


추후 상세 설명을 올리겠습니다...(언젠가...ㅠㅠ)



 

 import kr.jclab.cloud.ms3.server.spring.EnableMS3SpringServer;
 import kr.jclab.cloud.ms3.server.spring.MS3SpringServer;
 import kr.jclab.cloud.ms3.server.spring.MS3SpringServerConfigurerAdapter;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationContext;
 
 import java.io.File;
 
 @EnableMS3SpringServer
 public class MS3ServerConfig implements MS3SpringServerConfigurerAdapter {
 
  @Autowired
  ApplicationContext applicationContext;
 
  @Override
  public void configure(MS3SpringServer server) {
 server.setResourceDirectory(new File("D:\\test\\zeroupserver-resource"));
 server.registerRequestMapping("/ms3", Integer.MAX_VALUE - 2);
 }

}


서버는 이런식으로 @EnableMS3SpringServer Annotation으로 설정된 설정 클래스에 MS3SpringServerConfigurerAdapter을 구현해서 사용하시면 됩니다.

(서버 설정은 이게 끝이에요^^)


아 build.gradle의 dependency에 아래항목이 추가되어야 합니다.

// https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3
compile group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.470'

// https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc
compile group: 'org.xerial', name: 'sqlite-jdbc', version: '3.7.2'



클라이언트 사용법 : 

@RequestMapping(path = "list")
public ResponseEntity<Object> list() {
AmazonS3 s3 = MS3ClientBuilder.standard().serverUrl("http://localhost:9000/ms3/").build();
Object response = s3.listObjects("test");
return new ResponseEntity<>(response, HttpStatus.OK);
}

@RequestMapping(path = "test1")
public ResponseEntity<InputStreamResource> test1() {
AmazonS3 s3 = MS3ClientBuilder.standard().serverUrl("http://localhost:9000/ms3/").build();
S3Object response = s3.getObject("test", "bbbb");
System.err.println(response.getObjectMetadata());
return new ResponseEntity<>(new InputStreamResource(response.getObjectContent()), HttpStatus.OK);
}

이런식으로 AmazonS3와 호환됩니다~


build.gradle의 dependency에 아래항목이 추가되어야 합니다.

// https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3
compile group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.470'


사용 가능한 MS3Client (AmazonS3) 메서드들


v1.0.0

 - getUrl ( 절대경로가 아닌 상대경로형식으로 리턴됩니다! 예시: public/12345678-1111-2222-333333333333 )

 - listObjects

 - listObjectsV2

 - getObjectMetadata

 - getObject

 - putObject

 - getObjectAsString

 - deleteObject

v1.0.2

 - listBuckets

 - createBucket

v1.0.6

 - * directorySpliter 지원 (아래 참고)


지원하지 않는 메서드들

 - setEndpoint

 - setRegion

 - setS3ClientOoptions

 - changeObjectStorageClass

 - setObjectRedirectLocation

 - listNextBatchOfObjects

 - listVersions

 - listNextBatchOfVersions

 - getS3AccountOwner

 - getS3AccountOwner

 - doesBucketExist

 - doesBucketExistV2

 - headBucket

 - getBucketLocation

 - createBucket(region)

 - getObjectAcl

 - setObjectAcl

 - getBucketAcl

 - setBucketAcl

 - getObjectTagging

 - setObjectTagging

 - deleteObjectTagging

 - deleteBucket

 - copyObject

 - copyPart

 - deleteObjects

 - deleteVersion

 - getBucketLoggingConfiguration

 - setBucketLoggingConfiguration

 - getBucketLifecycleConfiguration

 - setBucketLifecycleConfiguration

 - deleteBucketLifecycleConfiguration

 - getBucketCrossOriginConfiguration

 - setBucketCrossOriginConfiguration

 - deleteBucketCrossOriginConfiguration

 - getBucketTaggingConfiguration

 - setBucketTaggingConfiguration

 - deleteBucketTaggingConfiguration

 - getBucketNotificationConfiguration

 - setBucketNotificationConfiguration

 - getBucketWebsiteConfiguration

 - setBucketWebsiteConfiguration

 - deleteBucketWebsiteConfiguration

 - getBucketPolicy

 - setBucketPolicy

 - deleteBucketPolicy

 - generatePresignedUrl

 - initiateMultipartUpload

 - uploadPart

 - listParts

 - abortMultipartUpload

 - completeMultipartUpload

 - listMultipartUploads

 - getCachedResponseMetadata

 - restoreObject

 - restoreObjectV2

 - enableRequesterPays

 - disableRequesterPays

 - isRequesterPaysEnabled

 - setBucketReplicationConfiguration

 - getBucketReplicationConfiguration

 - deleteBucketReplicationConfiguration

 - doesObjectExist

 - getBucketAccelerateConfiguration

 - setBucketAccelerateConfiguration

 - deleteBucketMetricsConfiguration

 - getBucketMetricsConfiguration

 - setBucketMetricsConfiguration

 - listBucketMetricsConfigurations

 - deleteBucketAnalyticsConfiguration

 - getBucketAnalyticsConfiguration

 - setBucketAnalyticsConfiguration

 - listBucketAnalyticsConfiguration

 - deleteBucketInventoryConfiguration

 - getBucketInventoryConfiguration

 - setBucketInventoryConfiguration

 - listBucketInventoryConfiguration

 - deleteBucketEncryption

 - getBucketEncryption

 - setBucketEncryption

 - setPublicAccessBlock

 - deletePublicAccessBlock

 - getBucketPolicyStatus

 - selectObjectContent

 - setObjectLegalHold

 - getObjectLegalHold

 - setObjectLockConfiguration

 - getObjectLockConfiguration

 - setObjectRetention

 - getObjectRetention

 - getRegion

 - getRegionName

 - 기타 Deprecated된 메서드들


권한관리같은거 없습니다.. 직접 spring-security으로 구현해서 쓰시구요...^^


metadata와 data는 모두 파일로 관리됩니다.

DB는 SQLite가 쓰이는데 그저 share-object(getUrl으로 가져온것)에 대한 정보만 저장합니다.


성능같은거 아직 신경쓰지 못하고 만든 prototype입니다..

개선 너무 감사하고 환영합니다^^


Apache License 2.0 라이센스를 사용합니다.




* v1.0.6 부터 directorySpliter를 지원합니다.

사용 방법은 아래와 같이 UserMetadata에서 "kr.jclab.cloud.ms4.directoryspliter"를 "true"혹은 "1" 로 설정하면 됩니다.

ObjectMetadata metadata = new ObjectMetadata();
metadata.addUserMetadata("kr.jclab.cloud.ms3.directoryspliter", "true");
s3.putObject("test", "object-a", is, metadata);

그럼 데이터가 아래와 같이 저장됩니다.

/data/test/meta-object-a34

/data/test/meta-object-a616

/data/test/meta-object-a47

/data/test/meta-object-a321

/data/test/dsdata-00/object-a34
/data/test/dsdata-00/object-a616

/data/test/dsdata-0a/object-a47

/data/test/dsdata-0a/object-a321


이와같이 data가 "dsdata-(이름hash의 첫번째 바이트)/이름" 으로 나늬어져서 저장됩니다.

Comment +0