ERROR 3141 (22032): Invalid JSON text in argument 1 to function json_contains: "Invalid value." at position 0.


에러 환경

 

Client OS: Windows10

Server OS: Ubuntu 22.04.2 LTS

MySQL: 8.0.30


에러 원인

 

JSON_CONTAINS 함수 사용할 때 인자값이 잘못되어 발생하는 에러입니다.

대부분 작은 따옴표('), 큰 따옴표(")를 잘못써서 발생합니다.


해결 방안

 

JSON_CONTAINS('컬럼', '1')

 

함수 파라미터를 전달할 때 작은 따옴표(')를 사용합니다.

 

JSON_CONTAINS('컬럼','"문자열"')

 

문자열을 전달할 때는 큰 따옴표(") 를 사용하고 다시 작음 따옴표(')로 감싸줘야 합니다. 


마무리

 

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

728x90
반응형

Json, 다중 Json 데이터 WHERE문 검색하기

 

MySQL 5.7 버전부터는 Json 타입의 데이터를 사용할 수 있습니다. Json 타입의 데이터를 검색하는 방법에 대해 알아봅시다.


테스트용 테이블 만들기

 

테이블 생성

# 테이블 생성 #
CREATE TABLE json_test (
	name varchar(8),
	data json
)

Query OK, 0 rows affected (0.01 sec)

# 테이블 확인 #
DESC json_test;
+-------+------------+------+-----+---------+-------+
| Field | Type       | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| name  | varchar(8) | YES  |     | NULL    |       |
| data  | json       | YES  |     | NULL    |       |
+-------+------------+------+-----+---------+-------+

2 rows in set (0.00 sec)

 

데이터 추가

# 데이터 추가 #
INSERT INTO json_test(name, data) VALUE ('test0','{"id":0, "value": { "name": "a", "array": [0, 2] } }');
INSERT INTO json_test(name, data) VALUE ('test1','{"id":1, "value": { "name": "b", "array": [0, 3] } }');
INSERT INTO json_test(name, data) VALUE ('test2','{"id":2, "value": { "name": "c", "array": [1, 2] } }');

# 데이터 확인 #
SELECT * FROM json_test;
+-------+----------------------------------------------------+
| name  | data                                               |
+-------+----------------------------------------------------+
| test0 | {"id": 0, "value": {"name": "a", "array": [0, 2]}} |
| test1 | {"id": 1, "value": {"name": "b", "array": [0, 3]}} |
| test2 | {"id": 2, "value": {"name": "c", "array": [1, 2]}} |
+-------+----------------------------------------------------+
3 rows in set (0.00 sec)

테스트용 테이블 검색하기

 

Json 검색

SELECT * FROM json_test
WHERE data->"$.id" = 0;
+-------+----------------------------------------------------+
| name  | data                                               |
+-------+----------------------------------------------------+
| test0 | {"id": 0, "value": {"name": "a", "array": [0, 2]}} |
+-------+----------------------------------------------------+
1 row in set (0.00 sec)

 

Json 타입 컬럼명 -> "$.필드이름" 형식을 이용하여 Json 데이터에 접근할 수 있습니다.

 

다중 Json 검색

SELECT * FROM json_test
WHERE data->"$.value.name" = "c";
+-------+----------------------------------------------------+
| name  | data                                               |
+-------+----------------------------------------------------+
| test2 | {"id": 2, "value": {"name": "c", "array": [1, 2]}} |
+-------+----------------------------------------------------+
1 row in set (0.00 sec)

 

Json 타입 컬럼명 -> "$.필드이름.필드이름" 형식을 이용하여 Json 속 Json 데이터에 접근할 수 있습니다.

 

Json 속 배열 검색

SELECT * FROM json_test
WHERE data->"$.value.array[0]" = 0;
+-------+----------------------------------------------------+
| name  | data                                               |
+-------+----------------------------------------------------+
| test0 | {"id": 0, "value": {"name": "a", "array": [0, 2]}} |
| test1 | {"id": 1, "value": {"name": "b", "array": [0, 3]}} |
+-------+----------------------------------------------------+
2 rows in set (0.00 sec)

 

Json 타입 컬럼명 -> "$.필드이름[n]" 형식을 이용하여 Json 속 배열 n번째 데이터에 접근할 수 있습니다.

 

Json 속 배열 전체 내 검색

SELECT * FROM json_test
WHERE JSON_CONTAINS(data->"$.value.array",'2');
+-------+----------------------------------------------------+
| name  | data                                               |
+-------+----------------------------------------------------+
| test0 | {"id": 0, "value": {"name": "a", "array": [0, 2]}} |
| test2 | {"id": 2, "value": {"name": "c", "array": [1, 2]}} |
+-------+----------------------------------------------------+
2 rows in set (0.00 sec)

 

JSON_CONTAINS(배열,값) 함수를 이용하여 특정값 배열이 있는 데이터를 찾을 수 있습니다.


마무리

 

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

728x90
반응형

 

파이썬 에러 Fatal error in launcher: Unable to create process using


에러 환경

 

OS: Windows10

Python: 3.8.6


에러 원인

 

대부분 python, pip의 경로가 서로 다르거나 권한이 없을때 에러가 발생합니다.

Fatal error in launcher: Unable to create process using '"d:\python_test\testpy\scripts\python.exe"  "D:\Python_test\Testpy\Scripts\pip.exe" install IP2Location': 
??? ??? ?? ? ????.

해결 방안

 

방법1.

python -m 명령어를 사용하여 pip를 사용하거나 pip를 재설치합니다.

# python -m 명령어를 사용하여 pip 사용 
python -m pip install 패키지

# pip 재설치
python -m pip install --upgrade --force-reinstall pip

 

 

방법2.

Windows 환경 변수를 등록합니다.

 

[윈도우키] + r 눌러 실행을 띄우고 sysdm.cpl ,3 를 실행시킵니다.

 

 

위와 같이 시스템 속성창이 뜨면 [환경변수]를 클릭합니다.

 

 

Path에 현재 사용중인 파이썬 위치를 등록해줍니다.

 

방법3.

가상환경을 사용할 경우 가상환경을 업데이트합니다. 

python -m venv --upgrade testpy

 

방법4.

PyCharm, VS Code, CMD 등 관리자 권한으로 실행합니다.


마무리

 

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

728x90
반응형

 

ERROR 3948 (42000): Loading local data is disabled; this must be enabled on both the client and server side


에러 환경

 

Client OS: Windows10

Server OS: Ubuntu 22.04.2 LTS

MySQL: 8.0.30


에러 원인

 

LOAD DATA LOCAL 명령어 사용시 서버측에서 권한이 없을때 발생합니다.


해결 방안

 

1. local_infile 권한이 있는지 확인합니다.

SHOW GLOBAL VARIABLES LIKE 'local_infile';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| local_infile  | OFF   |
+---------------+-------+
1 row in set (0.00 sec)

 

2. local_infile 권한이 OFF이면 명령어를 사용하여 ON으로 변경합니다.

SET GLOBAL local_infile=1;
Query OK, 0 rows affected (0.00 sec)

SHOW GLOBAL VARIABLES LIKE 'local_infile';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| local_infile  | ON    |
+---------------+-------+
1 row in set (0.00 sec)

 

3. 테스트

LOAD DATA LOCAL
	INFILE 'TEST_DATA.CSV'
INTO TABLE
	`test_data_info`
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\r\n'
IGNORE 0 LINES;
Query OK, 2964908 rows affected (20.86 sec)

연관성 있는 다른 에러

 

클라이언트측 local_infile 권한 문제

 

[MySQL] ERROR 2068 (HY000): LOAD DATA LOCAL INFILE file request rejected due to restrictions on access.

ERROR 2068 (HY000): LOAD DATA LOCAL INFILE file request rejected due to restrictions on access. 에러 환경 Client OS: Windows10 Server OS: Ubuntu 22.04.2 LTS MySQL: 8.0.30 에러 원인 LOAD DATA LOCAL 명령어 사용시 클라이언트측 CMD가 관

rurustory.com


마무리

 

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

 

728x90
반응형

 

ERROR 2068 (HY000): LOAD DATA LOCAL INFILE file request rejected due to restrictions on access.


에러 환경

 

Client OS: Windows10

Server OS: Ubuntu 22.04.2 LTS

MySQL: 8.0.30


에러 원인

 

LOAD DATA LOCAL 명령어 사용시 클라이언트측 CMD가 관리자권한이 없거나 --local-infile 권한이 없을때 발생합니다.


해결 방안

 

1. CMD 실행시 관리자 권한으로 실행시킵니다.

 

2. MySQL 접속시 --local-infile 옵션을 넣고 접속합니다.

mysql.exe --local-infile -u <유저> -p <DB명> -h <서버호스트> -P <접속포트>

 

3. 테스트

LOAD DATA LOCAL
	INFILE 'TEST_DATA.CSV'
INTO TABLE
	`test_data_info`
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\r\n'
IGNORE 0 LINES;
Query OK, 2964908 rows affected (20.86 sec)

연관성 있는 다른 에러

 

서버측 local_infile 권한 문제

 

[MySQL] ERROR 3948 (42000): Loading local data is disabled; this must be enabled on both the client and server side

ERROR 3948 (42000): Loading local data is disabled; this must be enabled on both the client and server side 에러 환경 Client OS: Windows10 Server OS: Ubuntu 22.04.2 LTS MySQL: 8.0.30 에러 원인 LOAD DATA LOCAL 명령어 사용시 서버측에서 권

rurustory.com


마무리

 

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

728x90
반응형

 

클래스를 DLL로 만들고 사용하기

 

클래스를 DLL로 만들고 사용하는 방법을 알아보겠습니다.


클래스 구조 코드 준비하기

 

헤더파일(.h파일)

#include <iostream>
using std::cout;
using std::endl;

#include <string>
using std::string;

class TestClass 
{
private:
	string stringTest;
	bool boolTest;
	int intTest;

public:
	TestClass();
	~TestClass();

	void SetString(string data);
	void SetBool(bool data);
	void SetInt(int data);

	string GetString();
	bool GetBool();
	int GetInt();
};

 

cpp파일

#include "ctest.h"

TestClass::TestClass() { cout << "Init TestClass!!" << endl; }
TestClass::~TestClass() { cout << "End TestClass!!" << endl; }

void TestClass::SetString(string data) { stringTest = data; }
void TestClass::SetBool(bool data) { boolTest = data; }
void TestClass::SetInt(int data) { intTest = data; }

string TestClass::GetString() {	return stringTest; }
bool TestClass::GetBool() { return boolTest; }
int TestClass::GetInt() { return intTest; }

 

위와 같이 DLL로 만들 클래스 구조의 코드를 준비합니다.


DLL Wrapper(래퍼) 선언부 만들기

 

헤더파일(.h파일)

#include "ctest.h"
#define DLL __declspec(dllexport)

extern "C" {
	DLL TestClass* CreateTestClass();

	DLL void SetString(TestClass* obj, string data);
	DLL void SetBool(TestClass* obj, bool data);
	DLL void SetInt(TestClass* obj, int data);

	DLL string GetString(TestClass* obj);
	DLL bool GetBool(TestClass* obj);
	DLL int GetInt(TestClass* obj);

	DLL void DeleteTestClass(TestClass* obj);
}

 

코드 설명

일반적인 DLL 만드는 방법과 동일하게 __declspec(dllexport) 명령어를 이용하여 DLL 라이브러리에서 호출가능한 함수로 만들어줍니다.

그리고 DLL에서 네임 맹글링된 함수를 가져오기 어렵기 때문에 extern "C" 명령어를 이용하여 네임 맹글링을 제거합니다.

이제부터 네임 맹글링을 하지않기 때문에 클래스를 사용하려면 클래스를 동적 할당하여 각 함수마다 동적 할당된 클래스의 주소를 알려주어야 합니다.

마지막으로 동적 할당하여 객체를 생성하였기 때문에 꼭 동적 할당 해제하는 함수도 만들어줘야 합니다.


DLL Wrapper(래퍼) 구현부 만들기

 

cpp파일

#include "ctestDLL.h"

TestClass* CreateTestClass() { return new TestClass(); }

void SetString(TestClass* obj, string data) { obj->SetString(data); }
void SetBool(TestClass* obj, bool data){ obj->SetBool(data); }
void SetInt(TestClass* obj, int data){ obj->SetInt(data); }

string GetString(TestClass* obj) { return obj->GetString(); }
bool GetBool(TestClass* obj){ return obj->GetBool(); }
int GetInt(TestClass* obj){ return obj->GetInt(); }

void DeleteTestClass(TestClass* obj) 
{
	if (obj) {
		delete obj;
		obj = nullptr;
	}
}

 

코드 설명

new를 이용하여 클래스를 동적할당하는 함수를 구현합니다.

각 함수에서는 동적할당한 클래스의 주소를 받고 동적할당한 클래스에서 함수를 다시 실행시켜야 합니다.

delete를 이용하여 꼭 동적할당해제를 해줘야합니다.


DLL 파일로 만들기

 

빌드 설정

 

빌드하기전에 [프로젝트 속성 > 구성 속성 > 일반] 에서 구성 형식을 동적 라이브러리(.dll)인지 꼭 확인해야합니다.

 

빌드 결과

빌드가 완료 되면 위와같이 dll파일과 lib파일이 생깁니다.

 

여기서 dll빌드를 하였는데 lib파일이 생기는건 암시적 링킹(Implicit linking)을 하였기 때문입니다. 좀 더 상세한 내용은 아래 포스팅을 통해 확인 할 수 있습니다.

 

https://rurustory.com/8

 

[C++] 정적 라이브러리(Static Link Library)와 동적 라이브러리(Dynamic Link Library)

정적 라이브러리(Static Link Library)와 동적 라이브러리(Dynamic Link Library) 개발을 할 때 자주쓰는 함수가 많아 중복을 최소화 하기위해 또는 협업을 효율적으로 하기위해 등등 각종 여러가지 이유로

rurustory.com


DLL 사용하기

 

이제 DLL을 만들었으니 새로운 프로젝트를 만들어 테스트를 해봅시다.

 

빌드 설정

 

1. [프로젝트 속성 > C/C++ > 일반] 에서 추가 포함 디렉터리에 dll의 헤더(.h 파일)가 있는 폴더경로를 설정해줍니다.

 

 

2. [프로젝트 속성 > 링커 > 일반] 에서 추가 라이브러리 디렉터리에 dll파일과 lib파일이 있는 폴더경로를 설정해줍니다.

 

 

3. [프로젝트 속성 > 링커 > 입력]에서 추가 종속성에 lib파일 이름을 입력해줍니다. 

 

Main cpp파일

#include "ctestDLL.h"

void main()
{
	TestClass* obj = CreateTestClass();

	SetString(obj, "Ruru TestString");
	SetBool(obj, true);
	SetInt(obj, 200);

	cout << "[GetString] " << GetString(obj) << endl;
	cout << "[GetBool] " << GetBool(obj) << endl;
	cout << "[GetInt] " << GetInt(obj) << endl;
    
	DeleteTestClass(obj);
}

 

빌드 결과

 

이제 빌드를 하면 정상적으로 빌드가 되는것을 확인할 수 있습니다.


마무리

 

지금까지 C++ 클래스를 DLL로 만들고 사용하는 방법이였습니다.

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

728x90
반응형

 

RSA 암호화 알고리즘 사용하기

 

Crypto++ 라이브러리로 RSA 개인키, 공개키를 생성하고 생성한 키로 암호화, 복호화하는 방법을 알아보겠습니다.


개인키, 공개키를 바이너리 키파일로 생성하기

 

샘플 코드

AutoSeededRandomPool rng;

RSA::PrivateKey privKey;
RSA::PublicKey pubKey;

privKey.GenerateRandomWithKeySize(rng, 2048);
pubKey = RSA::PublicKey(privKey);

ofstream privFile("private.key", ios::binary);
privKey.Save(FileSink(privFile).Ref() );
privFile.close();

ofstream pubFile("public.key", ios::binary);
pubKey.Save(FileSink(pubFile).Ref());
pubFile.close();

 

코드 설명

AutoSeededRandomPool rng;

 

RNG가 제공하는 OS를 사용하여 자체적으로 시드를 생성하는 함수입니다.

 

RSA::PrivateKey privKey;
RSA::PublicKey pubKey;

 

개인키, 공개키 객체를 생성합니다.

 

privKey.GenerateRandomWithKeySize(rng, 2048);

 

생성한 시드와 키 길이를 전달하여 개인키를 생성합니다.

 

pubKey = RSA::PublicKey(privKey);

 

개인키를 이용하여 공개키를 생성합니다.

 

ofstream privFile("private.key", ios::binary);
privKey.Save(FileSink(privFile).Ref() );
privFile.close();

ofstream pubFile("public.key", ios::binary);
pubKey.Save(FileSink(pubFile).Ref());
pubFile.close();

 

개인키와 공개키를 파일로 저장합니다.


개인키, 공개키를 Base64 키파일로 생성하기

 

샘플 코드

AutoSeededRandomPool rng;

RSA::PrivateKey privKey;
RSA::PublicKey pubKey;

privKey.GenerateRandomWithKeySize(rng, 2048);
pubKey = RSA::PublicKey(privKey);

ofstream privFile("private.key", ios::binary);
Base64Encoder privKeySink(new FileSink(privFile), true);
privKey.Save(privKeySink);
privKeySink.MessageEnd();
privFile.close();

ofstream pubFile("public.key", ios::binary);
Base64Encoder pubKeySink(new FileSink(pubFile), true);
pubKey.Save(pubKeySink);
pubKeySink.MessageEnd();
pubFile.close();

 

코드 설명

 

개인키, 공개키 생성 코드는 위와 동일하므로 설명을 생략하겠습니다.

 

ofstream privFile("private.key", ios::binary);
Base64Encoder privKeySink(new FileSink(privFile), true);
privKey.Save(privKeySink);
privKeySink.MessageEnd();
privFile.close();

ofstream pubFile("public.key", ios::binary);
Base64Encoder pubKeySink(new FileSink(pubFile), true);
pubKey.Save(pubKeySink);
pubKeySink.MessageEnd();
pubFile.close();

 

개인키와 공개키를 Base64로 인코딩하여 파일로 저장합니다.

Base64Encoder를 사용을 하면 반드시 MessageEnd() 함수를 사용해야합니다.

인코딩만 할때는 사용을 안해도 문제가 없었는데 나중에 디코딩할때 비정상적으로 디코딩이 되는 문제가 있었습니다. (이것때문에 엄청난 고생을.. ㅠㅠ) 


개인키, 공개키를 바이너리 문자열로 생성하기

 

샘플 코드

AutoSeededRandomPool rng;

RSA::PrivateKey privKey;
RSA::PublicKey pubKey;

privKey.GenerateRandomWithKeySize(rng, 2048);
pubKey = RSA::PublicKey(privKey);

string priv;
string pub;

privKey.Save(StringSink(priv).Ref());
pubKey.Save(StringSink(pub).Ref());

 

코드 설명

 

개인키, 공개키 생성 코드는 위와 동일하므로 설명을 생략하겠습니다.

 

string priv;
string pub;

privKey.Save(StringSink(priv).Ref());
pubKey.Save(StringSink(pub).Ref());

 

개인키와 공개키를 바이너리 문자열로 저장합니다.

string 타입의 변수이지만 바이너리 값이 들어갑니다.


개인키, 공개키를 Base64 문자열로 생성하기

 

샘플 코드

AutoSeededRandomPool rng;

RSA::PrivateKey privKey;
RSA::PublicKey pubKey;

privKey.GenerateRandomWithKeySize(rng, 2048);
pubKey = RSA::PublicKey(privKey);

string priv;
string pub;

Base64Encoder privKeySink(new StringSink(keyBuf.priv));
privKey.Save(privKeySink);
privKeySink.MessageEnd();

Base64Encoder pubKeySink(new StringSink(keyBuf.pub));
pubKey.Save(pubKeySink);
pubKeySink.MessageEnd();

 

코드 설명

 

개인키, 공개키 생성 코드는 위와 동일하므로 설명을 생략하겠습니다.

 

string priv;
string pub;

Base64Encoder privKeySink(new StringSink(keyBuf.priv));
privKey.Save(privKeySink);
privKeySink.MessageEnd();

Base64Encoder pubKeySink(new StringSink(keyBuf.pub));
pubKey.Save(pubKeySink);
pubKeySink.MessageEnd();

 

개인키와 공개키를 Base64 문자열로 저장합니다.

파일 생성때와 같은 이유로 꼭 MessageEnd() 함수를 사용해야합니다.


전체 예제 코드

#include <iostream>
using std::cout;
using std::endl;
using std::ofstream;
using std::ifstream;
using std::ios;

#include <string>
using std::string;

#include "rsa.h"
using CryptoPP::RSA;

#include "osrng.h"
using CryptoPP::AutoSeededRandomPool;

#include <files.h>
using CryptoPP::FileSink;
using CryptoPP::FileSource;

#include <filters.h>
using CryptoPP::StringSink;
using CryptoPP::StringSource;

#include <base64.h>
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;

struct KeyString 
{
	string priv;
	string pub;
};

void GenKeyFile(string fileName) 
{
	AutoSeededRandomPool rng;

	RSA::PrivateKey privKey;
	RSA::PublicKey pubKey;

	/* 개인키 생성 */
	privKey.GenerateRandomWithKeySize(rng, 2048);
	/* 공개키 생성 */
	pubKey = RSA::PublicKey(privKey);

	/* 개인키 가져오기 */
	ofstream privFile(fileName + "_private.key", ios::binary);
	privKey.Save(FileSink(privFile).Ref());
	privFile.close();
	/* 공개키 가져오기 */
	ofstream pubFile(fileName + "_public.key", ios::binary);
	pubKey.Save(FileSink(pubFile).Ref());
	pubFile.close();
}

void GenKeyFileBase64(string fileName) 
{
	AutoSeededRandomPool rng;

	RSA::PrivateKey privKey;
	RSA::PublicKey pubKey;

	/* 개인키 생성 */
	privKey.GenerateRandomWithKeySize(rng, 2048);
	/* 공개키 생성 */
	pubKey = RSA::PublicKey(privKey);

	/* 개인키 가져오기 */
	ofstream privFile(fileName + "_private.key", ios::binary);
	Base64Encoder privKeySink(new FileSink(privFile), true);
	privKey.Save(privKeySink);
	privKeySink.MessageEnd();
	privFile.close();

	/* 공개키 가져오기 */
	ofstream pubFile(fileName + "_public.key", ios::binary);
	Base64Encoder pubKeySink(new FileSink(pubFile), true);
	pubKey.Save(pubKeySink);
	pubKeySink.MessageEnd();
	pubFile.close();
}

KeyString GenKey() 
{
	AutoSeededRandomPool rng;

	RSA::PrivateKey privKey;
	RSA::PublicKey pubKey;

	/* 개인키 생성 */
	privKey.GenerateRandomWithKeySize(rng, 2048);
	/* 공개키 생성 */
	pubKey = RSA::PublicKey(privKey);

	KeyString keyBuf;

	/* 개인키 가져오기 */
	privKey.Save(StringSink(keyBuf.priv).Ref());
	/* 공개키 가져오기 */
	pubKey.Save(StringSink(keyBuf.pub).Ref());

	return keyBuf;
}

KeyString GenKeyBase64() 
{
	AutoSeededRandomPool rng;

	RSA::PrivateKey privKey;
	RSA::PublicKey pubKey;

	/* 개인키 생성 */
	privKey.GenerateRandomWithKeySize(rng, 2048);
	/* 공개키 생성 */
	pubKey = RSA::PublicKey(privKey);

	KeyString keyBuf;

	/* 개인키 가져오기 */
	Base64Encoder privKeySink(new StringSink(keyBuf.priv));
	privKey.Save(privKeySink);
	privKeySink.MessageEnd();

	/* 공개키 가져오기 */
	Base64Encoder pubKeySink(new StringSink(keyBuf.pub));
	pubKey.Save(pubKeySink);
	pubKeySink.MessageEnd();

	return keyBuf;
}

int main()
{
	cout << "\n###############################\n" << endl;
    
	/* Binary 키파일 */
	cout << "Binary KeyFile Start" << endl;
	GenKeyFile("RuruTest");
    
	cout << "\n###############################\n" << endl;

	/* Base64 키파일 */
	cout << "Base64 KeyFile Start" << endl;
	GenKeyFileBase64("RuruTest_Base64");
    
	cout << "\n###############################\n" << endl;

	/* Binary 문자열 키 */
	cout << "Binary Key Start" << endl;
	cout << endl;
    
	KeyString key;
	key = GenKey();

	cout << "PrivateKey:" << endl << key.priv << endl;
	cout << endl;
	cout << "PublicKey:" << endl << key.pub << endl;

	cout << "\n###############################\n" << endl;
    
	/* Base64 문자열 키 */
	cout << "Base64 Key Start" << endl;
	cout << endl;

	KeyString keyBase64;
	keyBase64 = GenKeyBase64();

	cout << "PrivateKey:" << endl << keyBase64.priv << endl;
	cout << endl;
	cout << "PublicKey:" << endl << keyBase64.pub << endl;

	cout << "\n###############################\n" << endl;
    
    return 0;
}

 


마무리

 

지금까지 Crypto++ 라이브러리로 RSA 개인키, 공개키 생성하는 방법이였습니다. 다음에는 개인키와 공개키가지고 암호화 복호화하는 방법을 작성 할 예정입니다.

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

728x90
반응형

 

Crypto++ 암호화 오픈 라이브러리

 

여러가지 암호화 알고리즘을 쉽게 사용할 수 있는 CryptoPP(Crypto++) 라이브러리에 대해 알아봅시다.


암호화 알고리즘 및 컴파일러 지원목록 (8.9 버전 기준)

 

컴파일러

- Visual Studio 2003 - 2022
GCC 3.3 - 13.1
Apple Clang 4.3 - 12.0
LLVM Clang 2.9 - 14.0
C++ Builder 2015
Intel C++ Compiler 9 - 16.0
Sun Studio 12u1 - 12.7
IBM XL C/C++ 10.0 - 14.0

 

암호화 알고리즘

인증된 암호화 체계 GCM, CCM, EAX, ChaCha20Poly1305, XChaCha20Poly1305
고속 스트림 암호 ChaCha (8/12/20), ChaCha (IETF) HC (128/256), Panama, Rabbit (128/256), Sosemanuk, Salsa20 (8/12/20), XChaCha (8/12/20), XSalsa20
AES 및 AES 후보 AES (Rijndael), RC6, MARS, Twofish, Serpent, CAST-256
다른 블록 암호들 ARIA, Blowfish, Camellia, CHAM, HIGHT, IDEA, Kalyna (128/256/512), LEA, SEED, RC5, SHACAL-2, SIMECK, SIMON (64/128), Skipjack, SPECK (64/128), Simeck, SM4,Threefish (256/512/1024), Triple-DES (DES-EDE2 and DES-EDE3), TEA, XTEA
블록 암호 동작 모드 ECB, CBC, CBC ciphertext stealing (CTS), CFB, OFB, counter mode (CTR), XTS
메시지 인증 코드 BLAKE2b, BLAKE2s, CMAC, CBC-MAC, DMAC, GMAC (GCM), HMAC, Poly1305, SipHash, Two-Track-MAC, VMAC
해시 함수 BLAKE2b, BLAKE2s, Keccack (F1600), SHA-1, SHA-2, SHA-3, SHAKE (128/256), SipHash, LSH (128/256), Tiger, RIPEMD (128/160/256/320), SM3, WHIRLPOOL
공개키 암호방법 RSA, DSA, Determinsitic DSA (RFC 6979), ElGamal, Nyberg-Rueppel (NR), Rabin-Williams (RW), EC-based German Digital Signature (ECGDSA), LUC, LUCELG, DLIES (variants of DHAES), ESIGN
공개 키 시스템에 대한 패딩 체계 PKCS#1 v2.0, OAEP, PSS, PSSR, IEEE P1363 EMSA2 and EMSA5
주요 합의 계획 Diffie-Hellman (DH), Unified Diffie-Hellman (DH2), Menezes-Qu-Vanstone (MQV), Hashed MQV (HMQV), Fully Hashed MQV (FHMQV), LUCDIF, XTR-DH
타원 곡선 암호법 ECDSA, Determinsitic ECDSA (RFC 6979), ed25519, ECGDSA, ECNR, ECIES, x25519, ECDH, ECMQV
하위 호환성 및 안전하지 않거나 오래된 알고리즘 MD2, MD4, MD5, Panama Hash, DES, ARC4, SEAL 3.0, WAKE-OFB, DESX (DES-XEX3), RC2, SAFER, 3-WAY, GOST, SHARK, CAST-128, Square
번외 16진수, base-32, base-64, URL safe base-64, 32비트 CRC, CRC-C, Adler32 checksum 등

 

좀 더 자세한 내용은 아래 링크에서 확인하시기 바랍니다.

https://cryptopp.com/index.html

 

Crypto++ Library 8.9 | Free C++ Class Library of Cryptographic Schemes

hash functions BLAKE2b, BLAKE2s, Keccack (F1600), SHA-1, SHA-2, SHA-3, SHAKE (128/256), SipHash, LSH (128/256), Tiger, RIPEMD (128/160/256/320), SM3, WHIRLPOOL

cryptopp.com


라이브러리 소스파일 준비

 

https://cryptopp.com/downloads.html

 

Crypto++ Library | All Downloads

The downloads page provides all downloads of the Crypto++ library. The earliest download available is Crypto++ 2.3 from January 1998. Crypto++ 1.0 was released in June 1995, but the download is no longer available. The hashes provided with a download were

cryptopp.com

 

홈페이지에서 cryptopp890.zip 파일을 다운받습니다.


Windows 버전

 

1. 라이브러리 빌드하기

 

압축해제를 하고 cryptest.sin 파일을 엽니다.

 

정적 라이브러리를 사용할꺼면 cryptlib, 동적 라이브러리를 사용할꺼면 cryptdll 프로젝트를 시작프로젝트로 설정후 빌드합니다.

 

저는 정적 라이브러리로 빌드하여 위와같이 cryptlib.lib 파일이 생성되었습니다.

 

2. 라이브러리 사용하기

 

이제 라이브러리 테스트를 해볼 프로젝트를 만들어 봅시다.

프로젝트를 만들었으면 아래와 같이 프로젝트 속성을 설정해 줍니다.

 

C/C++ -> 일반 -> 추가 포함 디렉터리: cryptopp 라이브러리 헤더파일이 있는곳으로 설정합니다.

 

 

C/C++ -> 코드 생성 -> 런타임 라이브러리를 다중 스레드(/MT)로 변경해줍니다.

 

 

링커 -> 일반 -> 추가 라이브러리 디렉터리를 Crypto++ 라이브러리를 빌드해서 생긴 lib파일이 있는곳으로 설정합니다.

 

 

링커 -> 입력 -> 추가 종속성에 lib파일 정보를 설정합니다.

 

#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;

typedef unsigned char byte;
typedef unsigned long long word64;

#include <base64.h>
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;

void main()
{
	string stringTest = "Ruru TestString";
	string encTest, decTest;

	/* 인코딩 시작 */
	Base64Encoder encoder;

	encoder.Put((const byte*)stringTest.data(), stringTest.size());
	encoder.MessageEnd();

	word64 encSize = encoder.MaxRetrievable();
	if (encSize)
	{
		encTest.resize(encSize);
		encoder.Get((byte*)&encTest[0], encTest.size());
	}

	cout << "Base64 Encode: " << encTest << endl;

	/* 디코딩 시작 */
	Base64Decoder decoder;

	decoder.Put((byte*)encTest.data(), encTest.size());
	decoder.MessageEnd();

	word64 decSize = decoder.MaxRetrievable();
	if (decSize && decSize <= SIZE_MAX)
	{
		decTest.resize(decSize);
		decoder.Get((byte*)&decTest[0], decTest.size());
	}

	cout << "Base64 Decode: " << decTest << endl;
}

 

다음은 문자열을 Base64 인코딩, 디코딩 하는 코드입니다. Crypto++ 라이브러리의 네임스페이스는 CryptoPP를 사용합니다. 

 

 

빌드를 하면 정상적으로 동작하는것을 확인할 수 있습니다.


Linux 버전

 

리눅스는 윈도우와 달리 좀더 간편하게 라이브러리를 빌드하고 사용할 수 할수있습니다.

 

1. 라이브러리 빌드하기

 

# 압축 해제 #
unzip cryptopp890.zip -d ./cryptopp890

# 압축 해제 폴더로 이동 #
cd cryptopp890

# 정적 라이브러리, 동적 라이브러리, 테스트파일 빌드 #
# 방법 1 #
make static dynamic cryptest.exe

# 방법 2 #
make libcryptopp.a libcryptopp.so cryptest.exe

# 빌드 확인 #
ls *.so *.a *.exe

 

2. 라이브러리 사용하기

 

이제 라이브러리가 준비되었으니 테스트파일을 만들어 테스트 해봅시다.

# cryptopp890 폴더에서 뒤로가기 #
cd ..

# 테스트용 cpp파일 생성 #
vi CryptoTest.cpp

 

#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;

typedef unsigned char byte;
typedef unsigned long long word64;

#include <base64.h>
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;

int main()
{
	string stringTest = "Ruru TestString";
	string encTest, decTest;

	/* 인코딩 시작 */
	Base64Encoder encoder;

	encoder.Put((const byte*)stringTest.data(), stringTest.size());
	encoder.MessageEnd();

	word64 encSize = encoder.MaxRetrievable();
	if (encSize)
	{
		encTest.resize(encSize);
		encoder.Get((byte*)&encTest[0], encTest.size());
	}

	cout << "Base64 Encode: " << encTest << endl;

	/* 디코딩 시작 */
	Base64Decoder decoder;

	decoder.Put((byte*)encTest.data(), encTest.size());
	decoder.MessageEnd();

	word64 decSize = decoder.MaxRetrievable();
	if (decSize && decSize <= SIZE_MAX)
	{
		decTest.resize(decSize);
		decoder.Get((byte*)&decTest[0], decTest.size());
	}

	cout << "Base64 Decode: " << decTest << endl;
    
    return 0;
}

 

# 테스트용 cpp파일 빌드 #
g++ -DNDEBUG -g3 -O2 -Wall -Wextra -o CryptoTest CryptoTest.cpp -I ./cryptopp890 ./cryptopp890/libcryptopp.a

 

윈도우와 똑같이 문자열을 Base64 인코딩, 디코딩 하는 코드입니다. Crypto++ 라이브러리의 네임스페이스는 CryptoPP를 사용합니다. 

 

빌드를 하면 정상적으로 동작하는것을 확인할 수 있습니다.


마무리

 

지금까지 Crypto++ 암호화 오픈 라이브러리에 대해 알아보았습니다. 추후 라이브러리를 통해 다양하게 암호화 하는 방법도 정리할 예정입니다.

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

728x90
반응형

Elasticsearch 명령어 모음

 

작업할때 빠르게 명령어를 찾을려고 정리해 놓습니다.


Index

 

모든 Index 확인

GET _cat/indices?v

 

Index 구조

GET [인덱스]

# pretty 사용하면 들여쓰기를 보기편하게 해준다 #
GET [인덱스]?pretty

 

Index 생성

PUT [인덱스]

 

Index 삭제

DELETE [인덱스]

 

Index 내 Document 개수

GET [인덱스]/_count

 

Index 열기

POST [인덱스]/_open

 

Index 닫기

POST [인덱스]/_close

Index 검색

 

전체 검색

GET [인덱스]/_search
{
    "query": {
        "match_all": {}
	}
}

# 콤마를 사용하여 Index 여러개를 동시에 검색 가능 #
GET [인덱스 1],[인덱스 2]/_search
{
    "query": {
        "match_all": {}
	}
}

# 와일드카드 사용가능 #
GET */_search
{
    "query": {
        "match_all": {}
	}
}

GET test*/_search
{
    "query": {
        "match_all": {}
	}
}

 

단일 검색

# 풀 텍스트 검색 #
GET [인덱스]/_search
{  
	"query":{  
		"match":{  
			"필드":"값"
		}
	}
}

# 정확하게 일치하는 텍스트만 검색 #
GET [인덱스]/_search
{
	"query": {
		"term": {
			"필드": "값"
		}
	}
}

 

기본적인 다중 검색

# 모든 조건이 일치 (검색 스코어 계산 O) #
GET [인덱스]/_search
{
	"query": {
		"bool": {
			"must": [ 
				{ "match": { "필드":"값" } },
				{ "match": { "필드":"값" } }
			]
		}
	}
}

# 조건중 하나이상 일치 (검색 스코어 계산 X) #
GET [인덱스]/_search
{
	"query": {
		"bool": {
			"filter": [
				{ "match": { "필드":"값" } },
				{ "match": { "필드":"값" } }
			]
		}
	}
}

# 모든 조건이 일치하지 않음 #
GET [인덱스]/_search
{
	"query": {
		"bool": {
			"must_not": [
				{ "match": { "필드":"값" } },
				{ "match": { "필드":"값" } }
			]
		}
	}
}

# 조건중 하나이상 일치 #
GET [인덱스]/_search
{
	"query": {
		"bool": {
			"should": [
				{ "match": { "필드":"값" } },
				{ "match": { "필드":"값" } }
			]
		}
	}
}

# 배열중 하나이상 일치 #
GET [인덱스]/_search
{
	"query": {
		"terms": {
			"필드": ["값 1","값 2","값 3"]
		}
	}
}

# 값1과 값2 사이 3자리 검색어 포함 검색 #
GET [인덱스]/_search
{
	"query": {
		"match_phrase": {
			"필드": {
				"query": "값1 값2",
				"slop": 3
			}
		}
	}
}

# 값1과 값2 사이 3자리 검색어 포함 검색 #
GET [인덱스]/_search
{
	"query": {
		"range": {
			"필드": {
				"gte": "크거나 같은 값",
				"gt": "큰 값",
				"lte": "작거나 같은 값",
				"lt": "작은 값"
			}
		}
	}
}

 

복합적인 다중 검색

# 특정 범위의 A or B 
GET [인덱스]/_search
{
	"query": {
		"bool": {
			"filter": [	  
			{
				"range": {
					"필드": {
						"gte": "크거나 같은 값",
						"gt": "큰 값",
						"lte": "작거나 같은 값",
						"lt": "작은 값"
					}
				}
			},
			{
				"bool":{
					"should": [
						{ "match": { "필드": "A값" } },
						{ "match": { "필드": "B값" } }
					]
				}
			}
		]
		}
	}
}

# (A and B) or (C and D) #
GET [인덱스]/_search
{
	"query": {
		"bool": {
			"should": [
				{ "bool": {
					"must":[
						{ "match": { "필드": "A 값" } },
						{ "match": { "필드": "B 값" } }
					]
				}
			},
				{ "bool": {
					"must":[
						{ "match": { "필드": "C 값" } },
						{ "match": { "필드": "D 값" } }
					]
				}
			}
			]
		}
	}
}

# (A or B) and (C or D) #
GET [인덱스]/_search
{
	"query": {
		"bool": {
			"must": [
				{ "terms": {
					"필드": ["A 값","B 값"]
					}
				},
				{ "terms": {
					"필드": ["C 값", "D 값"]
					}
				}
			]
		}
	}
}

 

검색 결과 가공

# 결과 개수 0페이지, 100개 #
GET [인덱스]/_search
{
	"query":{
		"match_all":{}
	},
	"from" : 0,
	"size" : 100,
}

# 결과 정렬 desc 내림차순, asc 오름차순 #
GET [인덱스]/_search
{
	"query":{
		"match_all":{}
	},
	"sort" : [
		{ "필드" : "desc" },
		{ "필드" : "asc" }
	]
}

# 집계 #
GET [인덱스]/_search
{
	"query":{
		"match_all":{}
	},
	"aggs":{
		"평균 임의필드": {
			"avg": {"field": "집계필드"}
		},
		"최솟값 임의필드": {
			"min": {"field": "집계필드"}
		},
		"최댓값 임의필드": {
			"max": {"field": "집계필드"}
		},
		"전체합계 임의필드": {
			"sum": {"field": "집계필드"}
		},
		"백분윗값 임의필드": {
			"percetiles": {"field": "집계필드"}
		},
		"avg,min,max,sum,count 값 임의필드": {
			"stats": {"field": "집계필드"}
		},
		"유니크값 임의필드": {
			"cardinality": {"field": "집계필드"}
		},
		"필드 내부위치 정보의 중심점 임의필드": {
			"geo-centroid": {"field": "집계필드"}
		}
	}
}

# 집계 데이터에서 다시 집계 #
GET [인덱스]/_search
{
	"query":{
		"match_all":{}
	},
	"aggs": {
    	"임의필드": {
      		"cardinality": { "field": "집계필드" }
		},
		"aggs": {
			"임의필드": {
				"min": { "field": "집계필드" }
			}
		}
	}
}

 


마무리

 

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

728x90
반응형

 

정적 라이브러리(Static Link Library)와 동적 라이브러리(Dynamic Link Library)

 

개발을 할 때 자주쓰는 함수가 많아 중복을 최소화 하기위해 또는 협업을 효율적으로 하기위해 등등 각종 여러가지 이유로 라이브러리를 사용하게 되는데 이번 시간에는 라이브러리가 어떤것들이 있는지 알아봅시다.


정적 라이브러리(Static Link Library)

 

정적 라이브러리는 컴파일을 하는 과정에서 애플리케이션이 필요로하는 라이브러리의 내용을 애플리케이션에다가 복사를 하여 사용하는 방법 입니다.

 

장단점

장점은 애플리케이션만 있으면 어디서든 실행을 시킬수 있다는 점이 있습니다.

단점은 애플리케이션에 라이브러리의 내용을 복사를 하였기 때문에 자체 용량이 커지며 라이브러리가 변동이 될 경우 애플리케이션을 전체 다시 빌드해야한다는 점이 있습니다.

 

정적 라이브러리의 확장자

Windows: .lib

Linux: .a


동적 라이브러리(Dynamic Link Library)

 

동적 라이브러리는 애플리케이션 실행할 떄 메모리에 위치하게 되며 라이브러리의 내용이 필요하게 되면 메모리에 있는 라이브러리를 사용하는 방법입니다.

 

장단점

장점은 정적 라이브러리를 사용하는 것보다 자체 용량이 작으며 라이브러리가 변동이 될 경우 애플리케이션 전체 빌드할 필요 없이 라이브러리만 바꾸면 된다는 점이 있습니다.

단점은 애플리케이션 실행할 때 라이브러리 파일이 필요하며 버전이 다르거나 호환이 되지 않는다면 사용하지 못하는 점이 있습니다.

 

동적 라이브러리의 확장자

Windows: .dll

Linux: .so


암시적 링킹(Implicit Linking)과 명시적 링킹(Explicit Linking)

 

윈도우에서 사용하는 동적 라이브러리(DLL) 에서는 애플리케이션에서 라이브러리를 호출하는 방법에 따라 암시적 링킹과 명시적 링킹으로 나누어집니다.

 

암시적 링킹(Implicit linking)

애플리케이션 자체에 DLL의 함수 정보를 포함시키는 방법이며 빌드 시 동적 라이브러리인 .dll 파일과 DLL이 제공하고자 하는 함수 정보가 포함되어 있는 .lib 파일이 생성됩니다.

이때 생성되는 .lib 파일은 정적 라이브러리로 생성한 .lib 파일과 확장자가 똑같아 같은 파일로 혼돈할 수 있지만 암시적 링킹으로 인해 생성된 .lib은 오로지 DLL의 제공 함수만 있기때문에 주의하시기 바랍니다.

 

명시적 링킹(Explicit linking)

애플리케이션이 실행할 때 .dll 파일의 존재만 확인을 하며 호출 할 함수의 주소를 얻어 함수를 실행시키는 방법 입니다.

 

 

암시적 링킹의 경우 컴파일러가 자동으로 해주는 경우가 많으며 사용하기 쉽기 때문에 편의성을 중시한다면 암시적 링킹을 사용하는것이 좋고 성능을 중시한다면 명시적 링킹을 사용하는것이 좋습니다.


마무리

 

지금까지 라이브러리 종류에 대해 알아보았습니다.

잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!

 

728x90
반응형

+ Recent posts