반응형
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | #include<stdio.h> #include<string.h> #include<stdlib.h> #include<sys/types.h> #include<signal.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<unistd.h> #include<sys/wait.h> #include <unistd.h> #include <time.h> #include <openssl/conf.h> #include <openssl/evp.h> #include <openssl/err.h> #define MAXLINE 514 void z_handler();// 시그널 처리 함수 static char base64_table[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' }; static char base64_pad = '='; unsigned char *base64_encode(const unsigned char *str, int length, int *ret_length) { const unsigned char *current = str; int i = 0; unsigned char *result = (unsigned char *)malloc(((length + 3 - length % 3) * 4 / 3 + 1) * sizeof(char)); while (length > 2) { /* keep going until we have less than 24 bits */ result[i++] = base64_table[current[0] >> 2]; result[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; result[i++] = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)]; result[i++] = base64_table[current[2] & 0x3f]; current += 3; length -= 3; /* we just handle 3 octets of data */ } /* now deal with the tail end of things */ if (length != 0) { result[i++] = base64_table[current[0] >> 2]; if (length > 1) { result[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; result[i++] = base64_table[(current[1] & 0x0f) << 2]; result[i++] = base64_pad; } else { result[i++] = base64_table[(current[0] & 0x03) << 4]; result[i++] = base64_pad; result[i++] = base64_pad; } } if (ret_length) { *ret_length = i; } result[i] = '\0'; return result; } /* as above, but backwards. :) */ unsigned char *base64_decode(const unsigned char *str, int length, int *ret_length) { const unsigned char *current = str; int ch, i = 0, j = 0, k; /* this sucks for threaded environments */ static short reverse_table[256]; static int table_built; unsigned char *result; if (++table_built == 1) { char *chp; for (ch = 0; ch < 256; ch++) { chp = strchr(base64_table, ch); if (chp) { reverse_table[ch] = chp - base64_table; } else { reverse_table[ch] = -1; } } } result = (unsigned char *)malloc(length + 1); if (result == NULL) { return NULL; } /* run through the whole string, converting as we go */ while ((ch = *current++) != '\0') { if (ch == base64_pad) break; /* When Base64 gets POSTed, all pluses are interpreted as spaces. This line changes them back. It's not exactly the Base64 spec, but it is completely compatible with it (the spec says that spaces are invalid). This will also save many people considerable headache. - Turadg Aleahmad <turadg@wise.berkeley.edu> */ if (ch == ' ') ch = '+'; ch = reverse_table[ch]; if (ch < 0) continue; switch (i % 4) { case 0: result[j] = ch << 2; break; case 1: result[j++] |= ch >> 4; result[j] = (ch & 0x0f) << 4; break; case 2: result[j++] |= ch >> 2; result[j] = (ch & 0x03) << 6; break; case 3: result[j++] |= ch; break; } i++; } k = j; /* mop things up if we ended on a boundary */ if (ch == base64_pad) { switch (i % 4) { case 0: case 1: free(result); return NULL; case 2: k++; case 3: result[k++] = 0; } } if (ret_length) { *ret_length = j; } result[k] = '\0'; return result; } void handleErrors(void) { ERR_print_errors_fp(stderr); abort(); } int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) { EVP_CIPHER_CTX *ctx; int len = 0; int ciphertext_len; /* Create and initialise the context */ if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); /* Initialise the encryption operation. IMPORTANT - ensure you use a key * and IV size appropriate for your cipher * In this example we are using 256 bit AES (i.e. a 256 bit key). The * IV size for *most* modes is the same as the block size. For AES this * is 128 bits */ if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) handleErrors(); /* Provide the message to be encrypted, and obtain the encrypted output. * EVP_EncryptUpdate can be called multiple times if necessary */ if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) handleErrors(); ciphertext_len = len; /* Finalise the encryption. Further ciphertext bytes may be written at * this stage. */ if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors(); ciphertext_len += len; /* Clean up */ EVP_CIPHER_CTX_free(ctx); return ciphertext_len; } int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx; int len; int plaintext_len; /* Create and initialise the context */ if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); /* Initialise the decryption operation. IMPORTANT - ensure you use a key * and IV size appropriate for your cipher * In this example we are using 256 bit AES (i.e. a 256 bit key). The * IV size for *most* modes is the same as the block size. For AES this * is 128 bits */ if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) handleErrors(); /* Provide the message to be decrypted, and obtain the plaintext output. * EVP_DecryptUpdate can be called multiple times if necessary */ if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) handleErrors(); plaintext_len = len; /* Finalise the decryption. Further plaintext bytes may be written at * this stage. */ if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors(); plaintext_len += len; /* Clean up */ EVP_CIPHER_CTX_free(ctx); return plaintext_len; } int main(int argc, char *argv[]) { /* A 256 bit key */ unsigned char *key = (unsigned char *)"01234567890123456789012345678901"; /* A 128 bit IV */ unsigned char *iv = (unsigned char *)"0123456789012345"; int server_sock; int client_sock; int clntlen; int num; int encoding_num = 0; int decoding_num = 1; char sendline[MAXLINE]; char recvline[MAXLINE]; char key_compare[MAXLINE]; int size; pid_t fork_ret; struct sockaddr_in client_addr; struct sockaddr_in server_addr; int state; struct sigaction act; act.sa_handler = z_handler; unsigned char ciphertext[MAXLINE]; unsigned char plaintext[MAXLINE]; /* Buffer for the decrypted text */ unsigned char decryptedtext[MAXLINE]; int decryptedtext_len, ciphertext_len; int encryptedtext_len, plaintext_len; char* test2; char* test3; /* Initialise the library */ ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); OPENSSL_config(NULL); if(argc!=2) { printf("Usage : %s PORT \n", argv[0]); exit(0); } // 소켓 생성 if((server_sock = socket(PF_INET, SOCK_STREAM, 0)) <0) { printf("Server : can't open stream socket. \n"); exit(0); } // 소켓 주소 구조체에 주소 세팅 bzero((char *)&server_addr, sizeof(server_addr)); // 소켓 주소 구조체 초기화 server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(atoi(argv[1])); sigaction(SIGCHLD, &act, 0); // 소켓에 서버 주소 연결 if(bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { printf("Server : can't bind local address.\n"); exit(0); } printf("Server started. \nWaiting for client.. \n"); listen(server_sock, 1); // 클라이언트의 연결요청 수락 clntlen = sizeof(client_addr); if((client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &clntlen)) <0) { printf("Server : failed in accepting. \n"); exit(0); } if((fork_ret = fork()) > 0) { // 부모 프로세스는 키보드 입력을 클라이언트로 송신 while(fgets(sendline, MAXLINE, stdin)!=NULL) { sendline[strlen(sendline)] = '\0'; size = strlen(sendline); printf("\n-------------- S E N D ----------------\n\n"); printf("SEND DATA : %s\n\n",sendline); if(size!=0){ ciphertext_len = encrypt(sendline, strlen(sendline), key, iv, ciphertext); ciphertext[ciphertext_len] = '\0'; printf("AES256 ( SEND DATA ) : %s \n\n",ciphertext); test2 = base64_encode((unsigned char *)ciphertext, ciphertext_len,&encoding_num); printf("BASE64ENCODING ( AES256 ( SEND DATA ) ) : %s \n\n",test2); if(write(client_sock, test2, strlen(test2)) == size) { printf("Error in write. \n"); } //memset(sendline,0x00,MAXLINE); //memset(test2,0x00,MAXLINE); //memset(ciphertext,0x00,MAXLINE); } } } else if(fork_ret == 0) { // 자식 프로세스는 클라이언트로부터 수신된 메시지를 화면에 출력 while(1) { memset(recvline,0x00,MAXLINE); if((size = read(client_sock, recvline, MAXLINE)) < 0) { printf("Error if read. \n"); close(client_sock); exit(0); } //recvline[strlen(recvline)] = '\0'; memset(plaintext,0x00,MAXLINE); printf("-------------- R E C E I V E -------------\n\n"); printf("BASE64ENCODING ( AES256 ( RECEIVE DATA ) ) : %s\n\n", recvline); // 화면 출력 test3 = base64_decode((unsigned char *)recvline, strlen(recvline),&decoding_num); printf(" AES256 ( RECEIVE DATA ) : %s\n\n", test3); // 화면 출력 plaintext_len = decrypt(test3, decoding_num, key, iv, plaintext); plaintext[plaintext_len] = '\0'; printf("RECEIVE DATA : %s\n\n", plaintext); // 화면 출력 } } close(server_sock); close(client_sock); return 0; } void z_handler() { int state; waitpid(-1, &state, WNOHANG); exit(0); return ; } | cs |
양방향 통신코드를 가져와서 openssl 라이브러리를 통한 AES256 암호화를 하였다.
양방향 소켓통신 출처 : http://yms2047.tistory.com/entry/%EC%96%91%EB%B0%A9%ED%96%A5-%ED%86%B5%EC%8B%A011-%EB%8C%80%ED%99%94
base 64 인코딩은 인터넷 어디선가 가져왔는데 주소가 기억나지 않는다.
base 64 인코딩은 openssl 라이브러리안에 존재한다고 한다. 그걸 사용하는것이 나을수 있어보인다.
동작화면은 아래와 같다.
반응형
'나는요 공부가 좋....은걸... > 암호화 + 소켓통신' 카테고리의 다른 글
C#소켓프로그래밍 (양방향 통신[Client]) + 암호화(AES256, base64) (1) | 2017.12.14 |
---|