初投稿!!
某決済システムで、3DESの暗号化・復号をすることになったのでメモですφ(..)
パッケージのインストール
僕はyarnを使ってるので、yarnで記載してます。
暗号化・復号にはcrypto-jsを使います。
XMLリクエストを投げる際にShiftJISに変換する必要がありますので、iconv-liteもインストールしておきます。
$ yarn add crypto-js iconv-lite
$ yarn add @types/crypto-js
準備
暗号化・復号に必要な値のパース
3DESで暗号化・復号を行います。
秘密鍵と初期化ベクトルはencでパースしてあげないとだめなんです。
これのやり方を理解してなくて苦戦しました。
import { enc } from "crypto-js"
const tripleDesEncryptKey = enc.Utf8.parse("xxxx");
const tripleDesIv = enc.Utf8.parse("xxx");
文字列のパディング
この決済サイトでは暗号化の際のPadding無しなので、暗号化する文字列は8バイトごとに半角スペースで埋める必要があります。
例えば暗号前の文字が3byte"abc"の場合
例
12345678
"abc "
例えば暗号前の文字が9byte"abcdefghi"の場合
例
1234567812345678
"abcdefghi "
これをtypescriptのコードにすると...
pad-space.ts
export function padSpace(input: string): string {
// ShiftJISに変換する
const sjisInput = iconv.encode(input, "Shift_JIS").toString();
const length = sjisInput.length - 1;
const paddedLength = 8 - (length % 8) + length;
return sjisInput.padEnd(paddedLength, " ");
}
※もっといい方法ないかな...
暗号化
encrypt.ts
import { TripleDES, mode, pad } from "crypto-js";
import { padSpace } from "./pad-space.ts";
const encrypt: string = TripleDES.encrypt( padSpace("暗号化したい文字列"), tripleDesEncryptKey, {
iv: tripleDesIv,
mode: mode.CBC,
padding: pad.NoPadding
}
).toString(); // TripleDES.encryptの返り値はWordArrayです。toString()でBASE64文字列として値を返します。
復号
基本同じ感じです。
encrypt.ts
import { TripleDES, mode, pad } from "crypto-js";
const decrypt: string = TripleDES.decrypt( "BASE64で暗号化された文字列"), tripleDesEncryptKey, {
iv: tripleDesIv,
mode: mode.CBC,
padding: pad.NoPadding
}
).toString(enc.Utf8).trim(); // 8byteごとにスペースで埋められた文字列が返ってくるので、trimしましょう
はまりどころ
phpとかだと秘密鍵と初期化ベクトルはそのまま文字列で値を渡してあげればいいのですが、
enc.Utf8.parseをつかってパースされた値を渡さないといけません。
※これがわからなくて一日ドハマリしました。
めんどくさい...
Shift JISに変換してますが、マルチバイトな文字列は返ってこないっぽいんで、不要な気がしてます。
そして次からStripeつかいます、ごめんなさい