JavaScript Node.js | crypto.createHmac()
crypto.createHmac() 매서드는 Hmac 객체를 생성하는데 사용된다.
기본 구조
crypto.createHmac(algorithm, key, options)
첫 번째 인자값 : 알고리즘 방식 ex) sha256, sha512
두 번째 인자값 : Hmac key값 (암호 HMAC hash 를 만드는데 사용)
It returns string, Buffer, TypedArray, DataView or KEyObject.
세 번째 인자값 : (Optional) - stream behavior 를 컨트롤 한다. It returns an object.
예시
const crypto = require('crypto');
function createPW(userpw){
const cryptoPassword = crypto.createHmac('sha256',Buffer.from(process.env.salt))
.update(userpw)
.digest('base64')
.replace('==','').replace('=','');
return cryptoPassword;
}
module.exports=createPW;
process.env.salt- 이미 dotenv 설치, 아래 any stirng 값을 입력했다. 아무 string이면 된다고 한다
.env 코드
SALT=ANYTHINGYOUCANWRITEHERETOMAKEITWORKASAKEYFORHASHALGORITHM
위의 cryptoPassword 암호화 과정을 살펴보면,
crypto.createHmac('sha256', Buffer.from(process.env.salt)).update(userpw).digest('base64').replace('==','').replace('=','')
crypto.createHmac('sha256', Buffer.from(process.env.salt)).update(userpw).digest('base64').replace('==','').replace('=','')
crypto.createHmac 의
첫 번째 인자값 : 암호방식 => 'sha256' 방식을 쓰겠다.
두번 째 인자값 :
process.env.salt 를 Buffer.from한 형태 => Stirng(암호화할 때 첨부하는 키값)을 바이너리 형식으로 바꾸겠다.
.update(userpw) => 그 값에 'sha256' 방식으로 암호화한 값에 userpw를 더하겠다.
.digest('base64') => userpw 까지 더한 암호 표현을 base64 방식 (글자 수를 굉장히 짧게 줄이는)으로 소화하겠다.
.replace('==','') => '==' 은 '' 빈값으로 바꾸겠다. (암호화하고 맨 끝에 '=' or '==' 이 뜰 때가 있음)
.replace('=','') => '=' 은 '' 빈값으로 바꾸겠다. (같은 이유)
각각의 내용 consol에서 보기
const crypto = require('crypto');
function createPW(userpw){ //createHmac 두번째 인자값 = any String like salt 암호화필요
const cryptoPassword = crypto.createHmac('sha256',Buffer.from('anystring'))
.update(userpw)
.digest('base64')
.replace('==','').replace('=','');
let a = Buffer.from('anystring')
let b = crypto.createHmac('sha256', Buffer.from('anystring'));
let c = crypto.createHmac('sha256', Buffer.from('anystring')).update(userpw);
let d = crypto.createHmac('sha256', Buffer.from('anystring')).update(userpw).digest('base64');
let e = crypto.createHmac('sha256', Buffer.from('anystring')).update(userpw).digest('base64').replace('=','');
console.log(a)
console.log(b)
console.log(c)
console.log(d)
console.log(e)
return cryptoPassword;
}
createPW('example');
module.exports=createPW;
다른 예제 , JWT 암호화 과정
require('dotenv').config();
const crypto = require('crypto');
function createToken(userid) {
let header = { "tpy": "JWT", "alg": "HS256", }
let exp = new Date().getTime() + ((60 * 60 * 2) * 1000) //1970.1.1부터 0 // 1월1일 1초지났으면 1000
let payload = {
userid, exp,
}
const encodingHeader = Buffer.from(JSON.stringify(header))
.toString('base64')
.replace('==', '').replace('=', '');
const encodingPayload = Buffer.from(JSON.stringify(payload)) // 요 안의 값을 다시 꺼내올예정
.toString('base64')
.replace('==', '').replace('=', '');
//console.log(encodingHeader, encodingPayload);
//암호화 시작 //첫번째 : 암호방식 /두번째인자 : key값 (이게 공개되면 해킹됨) - best-env
let signature = crypto.createHmac('sha256', Buffer.from(process.env.salt))
.update(encodingHeader + "." + encodingPayload)
.digest('base64')
.replace('==', '').replace('=', '');
let jwt = `${encodingHeader}.${encodingPayload}.${signature}`
return jwt;
}
module.exports = createToken;
복호화 과정 (암호 해독이 아닌 payload 안에 있는 내용 다시 빼내기)
JWT 암호를 만들기 위해 넣은 값 - payload 안의 내용을 꺼내오기
payload 만든 코드
순서 : 객체 -> 문자열 -> 바이너리 -> base64
const encodingPayload = Buffer.from(JSON.stringify(payload)) // 요 안의 값을 다시 꺼내올예정
.toString('base64')
.replace('==', '').replace('=', '');
1. JSON.stringify(payload) - payload를 문자열로 바꿔라 (payload 안 내용이 객체 -> JSON.stringify 쓴 이유)
2. Buffer.from(JSON.stringify(payload)) - 문자열로 바꾼 payload를 바이너리 형태로 바꿔라 (12 32 45 32 ... 이런 형태)
3. .toString('base64') - 바이너리 형태로 바꾼 걸 base64형태로 바꾸겠다. (글자수 확 줄이겠다.)
(4. replace('==','') - '==' 요 문자가 있으면 빈값으로 바꾸겠다. )
payload 안의 객체 내용 빼내기
위의 1,2,3 번을 (4번은 제외) 그대로 되돌리면 된다.
순서 : base64 -> 바이너리 -> 문자열 -> 객체
let { userid, exp } = JSON.parse(Buffer.from(payload, 'base64').toString());
1. Buffer.from(payload,'base64') - base64 형태로 바뀌었던 payload를 다시 바이너리 형태로 바꾸겠다.
2. Buffer.from(payload,'base64').toString() - 바이너리 형태로 바꾼걸 문자열로 바꿔라
3. JSON.parse( 위의 코드) - 문자열로 바꾼 것을 다시 parse 객체로 바꾸겠다.
질문 내용
require('dotenv').config();
const crypto = require('crypto');
const tokenKey = require('../jwt');
module.exports = (req, res, next) => { 질문 // 어쩔떄는 맨 아래 exports / 여기는 조금 다른 이유?
let accessToken = tokenKey('asdf');
let [header, payload, signature] = accessToken.split('.');
let signatureToCheck = signatureCheck(header, payload);
function signatureCheck() {
const signatureChecked = crypto.createHmac('sha256', Buffer.from(process.env.salt))
.update(header + '.' + payload)
.digest('base64')
.replace('==', '=').replace('=', '');
return signatureChecked
}
if (signature == signatureToCheck) {
console.log('검증')
let { userid, exp } = JSON.parse(Buffer.from(payload, 'base64').toString());
//질문 - 위의 코드 toString('base64')와 어떻게 다른지
console.log(userid, exp)
let newExp = new Date().getTime();
if (newExp > exp) {
console.log('토큰 만료');
redirect('/msg=토큰만료')
return 0;
}
req.userid=userid;
next();
} else {
console.log('실패')
res.redirect('/msg=해킹이다')
}
}
- 질문 답변 : toStirng - 글자 바꾼 형태를 Stirng할건데(이미 string임) base64로 / 그럼 toString('base64')는 이미 string으로 바뀐 문자열을 64로 바꾼다
let { userid, exp } = JSON.parse(Buffer.from(payload, 'base64').toString());
//질문 - 위의 코드 toString('base64')와 어떻게 다른지
// JWT 토큰 값 = accessToken (base64)로이미 변환된 글자
payload = base64 로 변환되어 있음 .toString() 원래 글자로 바꾼다. (디코딩) string을 객체로 바꿈
그럼 저기 (payload,'base64').toString() toSTring --> base64로 되어있는 문자열을--> b** console.log쳐보기
2 -> 16진수 연동잘됨
16 -> 64진수 변환 쉽다
64진수 좋은 점
10진수 ex) 10 == 0010 4칸 사용
16진수 ex) 10 == A 1칸 사용
64진수 -> 10진수의 글자들을 또 함축 가능
=>변환쉽고, 글자수도 줄여져서 , 특히 대량일 때.
'Javascript' 카테고리의 다른 글
[JavaScript 채팅창] div 스크롤 자동으로 내려가게 만드는 방법 (0) | 2021.06.15 |
---|---|
[JavaScript] Mysql2 로 DB data 비동기로 가져오기 예제 (0) | 2021.05.31 |
[JavaScript] 구조 분해 할당 [...] {...} 비구조화 할당 문법이란? 예시 / 자바스크립트 (0) | 2021.05.26 |
질문 [JavaScript] 자바스크립트 Object.keys() 사용법, 예제 (0) | 2021.05.26 |
[JavaScript] Switch ...case 조건문과 if ...else 차이는? 예제로 알아보기 자바스크립트 switch문 (1) | 2021.05.24 |