29. crypto encrypt 양방향 암호화
// 양방향 암호화
// 대칭형 암호화 (암호문 복호화 가능)
// - key가 사용됨
// - 암호화할 때와 복호화할 때 같은 key를 사용해야함
// ----------------------------------------------------------------------
const crypto = require('crypto');
const algorithm = 'aes-256-cbc';
const key = 'abcdefghijklmnopqrstuvwxyz123456'; // 32바이트
const iv = '1234567890123456'; // 16바이트
const cipher = crypto.createCipheriv(algorithm, key, iv);
let result = cipher.update('암호화할 문장', 'utf8', 'base64');
result += cipher.final('base64');
console.log(result); // iiopeG2GsYlk6ccoBoFvEH2EBDMWv1kK9bNuDjYxiN0=
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let result2 = decipher.update(result, 'base64', 'utf8');
result2 += decipher.final('utf8');
console.log(result2); // 암호화할 문장
// ----------------------------------------------------------------------
// 대칭형 암호화는 위와 같이 암호화, 복호화할 때 사용하는 algorithm, key, iv가 같다.
// ----------------------------------------------------------------------
// 그런데 이런 대칭형 암호화는 생각보다 취약하다.
// key만 탈취당하면 복호화해서 털리기 때문이다.
// 즉, 대칭형 암호화를 사용한다면, key, algorithm, iv 값 잘 관리해야된다.
// ----------------------------------------------------------------------
// 이런 대칭형 암호화는 '프론트 - 서버' 관계에선 사용할 수 없다.
// 프론트에 쓰이는 코드들은 다 노출된다.
// html, css, javascript 이런 것들이 모두 공개되어있다.
// 그런데 서버에서 뭔가를 암호화해서 보내줬는데, 그걸 프론트에서 해독하려면, 서버의 키와 프론트의 키가 같아야된다.
// 그런데 프론트에 그 키를 두면, 개발자 도구에서 해당 키를 볼 수가 있다.
// 그럼 해커들이 옳다구나하고 탈취해갈 것이다.
// 그래서 프론트 - 서버 관계 또는 한쪽이 공개된 부분이라면 같은 키를 사용하는 방식은 안된다.
// ----------------------------------------------------------------------
// 노드 예전 버전에선 createCipheriv 메서드 뒤에 iv가 없었다. (createCipher)
// 그런데 createCipher 메서드에서 취약점이 발견돼서..
// 초기화 백터 공격이라는게 있다.
// 암호화 자체는 배경지식이 없다면, 노드 관련 지식으로만 이해하기에 어려운 분야라..
// 여튼 초기화 백터 공격에 의해서 기존 createCipher 메서드의 간단한 암호화는 사라지고 createCipheriv 메서드가 추가되었다.
// 이 createCipheriv 메서드는 제약이 많아서
// key는 32바이트
// iv는 16바이트
// 문자열을 사용해야된다.
// 그리고 알고리즘도 하나 골라야된다.
// ----------------------------------------------------------------------
// 암호학 수업을 안 들으시면 왜 위와 같이 해야되는지 이해가 안 갈 수도 있다.
// npm에 crypto-js라는 남이 만들어놓은 모듈이 있는데,
// 이걸로 암호화를 하는걸 추천한다.
// 노드의 crypto는 암호학 지식이 있어야 원활하게 사용할 수 있고,
// 물론 crypto-js도 마찬가지긴 하다.
// 그래도 조금 더 쉽다.
// ----------------------------------------------------------------------
// 단방향 암호화: 해시 (sha512 추천)
// 대칭형 암호화: aes 추천
// 비대칭형 암호화: 프론트, 서버 서로 다른 키 사용
// - https 같은게 대표적인 비대칭형 암호화이다.
// - 비대칭형 암호화에선 rsa를 추천
// ----------------------------------------------------------------------
// 현업에서 비밀번호 salt 관리할 때는 git 같은데 올리면 안된다.
// .env도 git에 올리면 안된다.
// key 관리가 현업에서 제일 애매한데, aws kms(key management service)라는 서비스가 있다.
// 이런 서비스들을 쓰는 경우도 많고,
// 비밀번호도 관리 전략이 다양해서, 주기적으로 바꿔준다던가 자동화해주는 aws kms 같은 서비스도 있다.
// 비밀번호
// aws 로그인 비밀번호
// 배포를 위한 비밀번호
// 작은 회사들은 이런 비밀번호를 카톡으로 공유하기도하고, 슬랙으로 공유하기도하고
// 회사들은 항상 리스크를 가지고 있다.
// 높은 직급일 수록 많은 권한을 주고, 낮은 사람들한테는 권한이 낮은 키를 주고.
// 높은 직급인 사람이 이직할 때, 키를 들고 나갈 수도 있다.
// 한 사람이 나가면 그 키를 수정을 해야되는데,
// 그 사람에게 있던 키가 너무 많으면 힘들어진다. 그래서 kms 같은 서비스 사용도 고려해보는 것이 좋다.
// 하지만 정답이 있다기보다는 너무 어려운 주제이다.
// ----------------------------------------------------------------------
// 양방향 암호화 메서드 정리
// crypto.createCipheriv(알고리즘, 키, iv)
// 암호화 알고리즘과 키, 초기화 벡터를 넣어준다.
// - 암호화 알고리즘은 aes-256-cbc를 사용한다. 다른 알고리즘을 사용해도 된다.
// - 사용 가능한 알고리즘 목록은 crypto.getCiphers()를 하면 볼 수 있다.
// - 키는 32바이트, 초기화벡터(iv)는 16바이트로 고정이다.
// cipher.update(문자열, 인코딩, 출력 인코딩)
// 암호화할 대상과 대상의 인코딩, 출력 결과물의 인코딩을 넣어준다.
// - 보통 문자열은 utf8 인코딩을, 암호는 base64를 많이 사용한다.
// cipher.final(출력 인코딩)
// 출력 결과물의 인코딩을 넣어주면 암호화가 완료된다.
// crypto.createDecipheriv(알고리즘, 키, iv)
// 복호화할 때 사용한다.
// 암호화할 때 사용했던 알고리즘, 키, iv를 그대로 넣어줘야된다.
// decipher.update(문자열, 인코딩, 출력 인코딩)
// 암호화된 문장, 그 문장의 인코딩, 복호화할 인코딩을 넣어준다.
// - createCipher의 update()에서 utf8, base64 순으로 넣었다면 createDecipheriv의 update()에서는 base64, utf8 순으로 넣으면 된다.
// decipher.final(출력 인코딩): 복호화 결과물의 인코딩을 넣어준다.
// ----------------------------------------------------------------------
// 나중에 실제 서비스 만들 때 필요한 암호화 정도, 예시를 보여드리도록 하겠다.
// ----------------------------------------------------------------------
// 보통 암호화 알고리즘에서 뚫리는게 아니라 사람 실수에서 뚫린다.
// 비밀번호를 쉬운걸 한다던지 실수로 console에 찍거나 log에 남기거나 그런거에서 다 뚫린다.