aes-256-cbc란?
aes
- 고급 암호화 표준(Advanced Encryption Standard, AES)은 2001년 미국 표준 기술 연구소(NIST)에 의해 제정된 암호화 방식
- 암호화와 복호화 과정에서 동일한 키를 사용하는 대칭 키 알고리즘
- AES는 ISO/IEC 18033-3 표준에 포함되어 있으며 여러 암호화 패키지에서 사용
256
cbc
- aes 알고리즘과 함께 사용되는 블록 암호 모드
- Cipher Block Chaining의 약자
- AES처럼 데이터를 일정한 크기의 블록으로 나눠서 암호화하는 '블록 암호' 방식에서 사용하는 여러 가지 '운용 모드(Operating Mode)' 중 하나
- 각 블록을 암호화할 때 바로 이전에 암호화된 블록의 암호문과 현재 평문 블록을 XOR 연산하는 방식
- 맨 처음 블록을 암호화할 때는 '초기화 벡터(IV, Initialization Vector)'라는 값을 사용
암호화 방법
aes-256-cbc 생성해보기
echo password | openssl aes-256-cbc -k key -e -p -pbkdf2 -out output && cat output
salt=A02E8E4135B862BA
key=DB96C3D6AADA30923798183CCBBAD7E014434429B6084AF0A07DC739F5D57D26
iv =AB6CF2CA1740B6C97FD4E6C2478376C5
Salted__�.�A5�b��0�9L�▒]���f4��%
옵션 설명
- k : passphrase (긴 비밀번호)
- e : 암호화 (encrypt)
- p : print iv, key
- pbkdf2 : Password-Based Key Derivation Function 2의 약자
- 사용하는 비밀번호나 passphrase 같은 걸 이용해서 암호화에 사용할 '키'를 안전하게 만들어내는 함수
- out : outfile 생성
aes-256-cbc + base64
- 위에서 보듯이 aes는 보기 어렵고 다른데다 저장하기 어렵다. 따라서 해당 암호를 옮기기가 쉽지 않아 유저들이 들고다니기 좋도록 base64로 인코딩을 한 번 한다.
옵션 설명
echo password | openssl aes-256-cbc -k forty2 -e -p -pbkdf2 -out output -a && cat output
salt=BB85AD94FA0A73AD
key=1D35324FA0770B96974BF63BEF75C292828136ECA5BEABAAC8F0A38EB6AF1CFF
iv =DF24AE7B9DD0C7955863FCD562816E02
U2FsdGVkX1+7ha2U+gpzrR2SXAj8zrwnrGv988jlrXY=
복호화 하기
- PBKDF2_ITER 의 openssl 기본 값은 1만번이므로 define 해준다.
- aes 값은 헤더인 "salted__" + salt[8] + ciphertext 생성
- passphrase + salt를 통하여 iv[16] + key[32] 로 분리 하여 복호화
- IV : Initialization Vector 즉, 초기화 벡터 - 암호화의 보안을 강화하기 위해 사용하는 난수
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#define PBKDF2_ITER 10000
#define IV_LEN 16
#define KEY_LEN 32
#define AES_HEADER_LEN 8
#define SALT_LEN 8
void decode_aes_pbkdf2(unsigned char *aes_256_cbc, int aes_len, unsigned char *passphrase, char *password_buf) {
unsigned char salt[8] = {0};
unsigned char buf[4096] = {0};
unsigned char key[KEY_LEN] = {0};
unsigned char iv[IV_LEN] = {0};
int len = 0;
int total_len = 0;
int header_and_salt_len = AES_HEADER_LEN + SALT_LEN;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
memcpy(salt, aes_256_cbc + 8, 8);
PKCS5_PBKDF2_HMAC(passphrase, strlen(passphrase), salt, strlen(salt), PBKDF2_ITER, EVP_sha256(), IV_LEN + KEY_LEN, buf);
memcpy(key, buf, KEY_LEN);
memcpy(iv, buf + KEY_LEN, IV_LEN);
if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) {
strcpy(buf, "EVP init error check salt and passphrase\n");
goto aes_error;
}
if (!EVP_DecryptUpdate(ctx, (unsigned char *)password_buf, &len, \
aes_256_cbc + header_and_salt_len, aes_len - header_and_salt_len)) {
strcpy(buf, "decrypt update error \n");
goto aes_error;
}
total_len = len;
if (!EVP_DecryptFinal_ex(ctx, (unsigned char *)password_buf + len, &len)) {
fprintf(stderr, "decrypt text : %s \n", password_buf);
strcpy(buf, "decrypt final error\n");
goto aes_error;
}
total_len += len;
password_buf[total_len] = 0;
EVP_CIPHER_CTX_free(ctx);
printf("create decode aes file\n");
int fd = open("c_aes", O_WRONLY | O_CREAT | O_TRUNC, 0644);
write(fd, password_buf, strlen(password_buf));
close(fd);
return ;
aes_error:
EVP_CIPHER_CTX_free(ctx);
password_buf[0] = 0;
fprintf(stderr, buf);
}
void decode_pwd(char *base64_pwd, unsigned char *plaintext) {
int len;
unsigned char aes[4096] = {0};
len = strlen(base64_pwd);
fprintf(stderr,"base 64 len is %d in pwd\n", len);
if (len < 1) {
fprintf(stderr, "DB_PWD empty in sysconfig\n");
printf("input : %s\n", base64_pwd);
plaintext[0] = 0;
return;
}
len = EVP_DecodeBlock(aes, base64_pwd, len);
if (len < 1) {
fprintf(stderr, "Decode fail\nCheck password\n");
plaintext[0] = 0;
return;
}
fprintf(stderr, "full:%6s|hex:%X\n", aes,aes + strlen("salted__"));
decode_aes_pbkdf2(aes, len - 1, "forty2", plaintext);
}
int main() {
int fd;
char *base64 = "U2FsdGVkX1+7ha2U+gpzrR2SXAj8zrwnrGv988jlrXY=";
int len;
char plaintext[1024] = {0};
printf("read: %s|len:%d\n",base64 ,strlen(base64));
decode_pwd(base64, plaintext);
printf("Decoded password: %s[padding]\n", plaintext);
}
reference