SM4 の鍵長
16 バイト ちょうど 128 ビット、つまり 16 バイトで、16 進数 32 桁または ASCII 16 文字で表記します。192 ビットや 256 ビットの SM4 鍵は存在しません。
SM4 の暗号化と復号をオンラインで。復号に失敗したら、モード・パディング・IV・エンコーディングのどれが合っていないかを突き止め、修正後の設定を示します。処理はブラウザ内で完結し、データはアップロードされません。ECB・CBC・CTR・CFB・OFB、PKCS#7・ゼロパディング・パディングなしに対応。
ECB は同じブロックを同じ暗号文に変換するため、パターンが漏れます。ECB を必須とするシステムとの連携にだけ使ってください。
CTR・CFB・OFB はストリームモードです。パディングはなく、暗号文は平文と同じ長さになります。
自動診断
—
OpenSSL 3 が必要です。コマンドには入力した鍵が含まれます。
| 鍵 | 0123456789abcdeffedcba9876543210 |
|---|---|
| 平文 | 0123456789abcdeffedcba9876543210 |
| 暗号文(1 回暗号化) | 681edf34d206965e86b3e94f536e4246 |
| 暗号文(100 万回暗号化) | 595298c7c6fd271f0402f804c33d3f66 |
暗号ツールを開発するエンジニアが執筆・レビューしています。このページに記載した暗号文とバイト数は、すべてツールのエンジンで算出し、テストで検証しています。
16 バイト ちょうど 128 ビット、つまり 16 バイトで、16 進数 32 桁または ASCII 16 文字で表記します。192 ビットや 256 ビットの SM4 鍵は存在しません。
681edf34d206965e86b3e94f536e4246 鍵と平文を 0123456789abcdeffedcba9876543210 にすると、1 回の暗号化で 681edf34d206965e86b3e94f536e4246 になります。
32 ラウンド 16 バイト(128 ビット)のブロックを、32 ラウンドで暗号化します。
先頭 16 バイト なりません。正しく復号できないのは先頭 16 バイトだけで、最後のブロックにあるパディングの検証は通ります。
SM4 は、中国の商用暗号標準(国密)に含まれるブロック暗号です。GM/T 0002-2012 として公布された後、国家標準 GB/T 32907-2016(2017 年 3 月 1 日施行)となり、2021 年の追補によって国際標準 ISO/IEC 18033-3 にも追加されました。暗号化と復号に同じ 128 ビットの鍵を使う共通鍵暗号で、128 ビット、つまり 16 バイト単位のブロックを処理します。ブロック長は AES と同じです。
内部では、各ブロックを 32 ビットのワード 4 つに分け、32 ラウンドの処理を行います。各ラウンドでは 3 つのワードをラウンド鍵と混ぜ、その結果を 8 ビットの S ボックスと線形変換に通してから、4 つ目のワードに畳み込みます。32 個のラウンド鍵は 2 組の固定定数を使って鍵から導出されます。復号は、ラウンド鍵を逆順に使うだけで暗号化と同じ計算です。
ブロック暗号そのものが扱えるのはちょうど 16 バイトだけなので、実際のデータは必ず暗号利用モードを通します。このツールは代表的な 5 つのモードに対応しています。ブロック単位で処理しパディングが必要な ECB と CBC、そして SM4 をストリーム暗号として使い、パディングが一切不要な CTR・CFB・OFB です。復号の失敗は、ほとんどの場合 SM4 自体とは関係ありません。モード、パディング、IV、テキストのエンコーディング、鍵文字列をバイト列にする方法について双方の認識が食い違っていることが原因です。単に「SM4」と書いたときに何を指すのかさえ、ライブラリ間で一致していません。
ブラウザ組み込みの Web Crypto API は SM4 に対応していないため、このページは独自の実装を持ち、ローカルで実行します。GB/T 32907 の 2 つのテストベクトルでテストし、すべてのモードで OpenSSL 3 と照合しています。
// SM4-CBC with PKCS#7 padding using Node.js and its bundled OpenSSL 3.
// Key and IV are both exactly 16 bytes (32 hex digits).
const crypto = require('node:crypto');
const key = Buffer.from('0123456789abcdeffedcba9876543210', 'hex');
const iv = Buffer.from('fedcba98765432100123456789abcdef', 'hex');
const cipher = crypto.createCipheriv('sm4-cbc', key, iv);
const ciphertext = Buffer.concat([cipher.update('hello', 'utf8'), cipher.final()]);
console.log(ciphertext.toString('base64')); // fUQPRg2HAXHGz5ZslzCpSQ==
const decipher = crypto.createDecipheriv('sm4-cbc', key, iv);
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
console.log(plaintext.toString('utf8')); // hello 復号に失敗すると、暗号文のエンコーディング、鍵の形式、モード、IV、パディング、テキストのエンコーディングを変えて再試行し、読めるテキストになる設定を表示します。
OpenSSL、Hutool、sm-crypto、gm-crypt、tjfoc/gmsm の既定値を 1 クリックで設定できます。これらのライブラリは、単に「SM4」と書いたときに ECB と CBC のどちらを指すのかさえ一致していません。
ECB・CBC・CTR・CFB・OFB と、PKCS#7・ゼロパディング・パディングなしを組み合わせられます。平文は UTF-8 のほか、古い Java コードが中国語版 Windows 上で生成する GBK にも対応します。GCM には対応していません。
16 バイトの鍵や IV を 1 クリックでランダム生成できるほか、コードに書かれている形式のまま入力することもできます。リアルタイムのバイト数カウンターで、ほかの原因を探し始める前に、ちょうど 16 バイトあることを確認できます。
付録 A の 2 つの結果を表にまとめ、1 クリックで読み込めるようにしているので、どんな SM4 実装でも標準と照合できます。
すべての結果に、それを再現する openssl enc コマンドが付くので、ターミナルで確かめたり同僚に渡したりできます。
SM4 エンジンはローカルで動作します。鍵やデータがページの外に出ることはなく、オフラインでも使い続けられます。
openssl enc)-sm4 = CBC -sm4 は -sm4-cbc のエイリアスです。-K と -iv は 16 進数で指定し、-nopad を渡さない限り PKCS#7 は有効のまま、-base64 -A を付けなければ出力は生のバイト列です。長さの合わない -K は、警告が出るだけで切り詰められるかゼロで埋められます。
SmUtil.sm4(key)Hutool は SM4 という名前だけを渡し、BouncyCastle はそれを ECB と PKCS#7(JCE での名称は PKCS5Padding)で実行します。文字列メソッドは UTF-8 を使い、encryptHex は小文字の 16 進数を出力します。CBC を使うには new SM4(Mode.CBC, Padding.PKCS5Padding, key, iv) と書きます。
Cipher.getInstance("SM4")IV が必要なモードで IV を渡さないと、暗号化では黙ってランダムな IV が生成され、復号では no IV set when one expected がスローされます。つまり、その IV を保存せずに暗号化した暗号文は、どこでも復号できません。
sm4.encrypt(data, key) の既定は ECB と PKCS#7 で、鍵には 32 桁の 16 進数文字列を想定し、小文字の 16 進数を返します。モードが変わるのは mode: 'cbc' を指定したときだけで、それ以外の値では黙って ECB のままになります。sm-crypto-v2 も同じ動作ですが、CBC で iv が渡されないとオールゼロの IV を使います。
既定は CBC で、鍵と IV を 16 文字の UTF-8 文字列として受け取り、Base64 を返します。バイト列が有効な UTF-8 にならない鍵は、そもそも渡すことができません。
CryptSM4モードは crypt_ecb と crypt_cbc のどちらを呼ぶかで選びます。set_key は先頭 16 バイトしか読まないため、長い鍵は黙って切り詰められます。また、鍵が間違っていても、たいていエラーではなく空のバイト列が返ります。
sm4Sm4Cbc はパッケージレベルの IV を使い、その IV は SetIV を呼ぶまでオールゼロのままです。CFB や OFB でも PKCS#7 でパディングし、パディング除去のエラーは破棄します。そのため鍵が間違っていても、エラーなしで nil が返ります。
鍵 0123456789abcdeffedcba9876543210、平文(hex)0123456789abcdeffedcba9876543210
681edf34d206965e86b3e94f536e4246
GB/T 32907-2016 付録 A の例 1 です。鍵と平文は同じ 128 ビットの値で、1 回暗号化すると 681edf34d206965e86b3e94f536e4246 になります。その出力をさらに暗号化し続け、合計 100 万回暗号化すると 595298c7c6fd271f0402f804c33d3f66 になります。どちらの値も、いま使っているのと同じエンジンで算出し、このページのテストベクトル表に掲載しています。GB/T 32907 テストベクトル ボタンで 1 つ目の値を読み込めます。
鍵 0123456789abcdeffedcba9876543210、IV fedcba98765432100123456789abcdef、平文:SM4 interop test: order 20260911-0042
Wi6BuLpov8RndEfedUyLXFvDRnLMoo7T6O04Q83IzKDuDvPQ2S5clq+cEQXMvy/y
平文は UTF-8 で 37 バイトです。PKCS#7 によって 48 バイト(16 バイトのブロック 3 つ)にパディングされ、Base64 では 64 文字になります。サンプルを読み込む ボタンを押すとまさにこの値が入力され、OpenSSL パネルには同じ Base64 文字列をターミナルで再現するコマンドが表示されます。
上の暗号文を IV 00000000000000000000000000000000 で復号
16 バイト分の化けたデータの後に ": order 20260911-0042"
CBC で IV が混ざるのは最初のブロックだけで、PKCS#7 のパディングは最後のブロックにあります。そのためパディングのチェックは通り、OpenSSL もエラーを出しません。このページは先頭ブロックが読めないことを検知し、鍵とモードは正しく IV に問題があること、あるいは暗号文の先頭 16 バイトそのものが IV であることを知らせます。
相手側のライブラリがわかっていれば、「ライブラリの既定値に合わせる」で選びます。わからなければ暗号化か復号を選び、モードとパディングを相手に合わせます。ストリームモード(CTR・CFB・OFB)にはパディングがないため、これらのモードではパディングの選択欄が無効になります。
どちらもちょうど 16 バイトです。文字列の表記形式(16 進数・テキスト・Base64)を選び、バイト数カウンターが緑に変わることを確認します。「ランダム生成」ボタンで新しい値を作れます。
暗号化では、テキスト(UTF-8 または GBK)を入力するか、16 進数のバイト列を貼り付けます。復号では、暗号文を貼り付けて Base64 か 16 進数かを指定します。結果は入力と同時に更新されます。
出力をコピーするか、「この暗号文を復号」をクリックして、同じ鍵と IV のまま復号タブへ引き継ぎます。OpenSSL パネルには、結果を再現するコマンドが表示されます。
診断結果には、入力が読めるテキストに復号される設定が一覧表示されます。クリック 1 回で適用するか、先頭 16 バイトだけが失敗している場合は表示される注記を読んでください。それは IV が原因であることを示しています。
32 文字の 16 進数文字列が 16 バイトになるのは、16 進数としてデコードした場合だけです。テキストとして読むと 32 バイトになり、SM4 に拒否されます。鍵を黙って切り詰めたり埋めたりするコードでは、まったく別の鍵として扱われます。
鍵(テキスト): 0123456789abcdeffedcba9876543210 -> 32 バイト、拒否される
鍵(16 進数): 0123456789abcdeffedcba9876543210 -> 16 バイト
双方で同じモードを使う必要があります。CBC の暗号文を ECB として復号すると、すべてのブロックが化け、たいてい最後のパディングチェックでも失敗します。
暗号化: SM4/CBC/PKCS5Padding 復号: SM4/ECB/PKCS5Padding -> bad decrypt
暗号化: SM4/CBC/PKCS5Padding 復号: SM4/CBC/PKCS5Padding、IV も同じ
CBC では IV が間違っていてもエラーは出ません。先頭 16 バイトが化け、残りは正常に復号されます。平文の冒頭だけが壊れているなら、双方の IV を比べてください。
復号 IV 00000000000000000000000000000000 -> 16 バイトの化けたデータ + ": order 20260911-0042"
復号 IV fedcba98765432100123456789abcdef -> "SM4 interop test: order 20260911-0042"
Base64 と 16 進数は、同じバイト列の 2 通りの書き方です。一方を他方として読むと、最初から間違った入力を暗号に渡すことになります。
Wi6BuLpov8RndEfedUyLXFvDRnLMoo7T6O04Q83IzKDuDvPQ2S5clq+cEQXMvy/y 16 進数として読む -> 無効
Wi6BuLpov8RndEfedUyLXFvDRnLMoo7T6O04Q83IzKDuDvPQ2S5clq+cEQXMvy/y Base64 として読む -> 48 バイト
ゼロパディングはパディングとデータを区別できないため、本当に 0x00 で終わる平文はそのバイトを失います。プレーンテキスト以外のデータには PKCS#7 を使ってください。
ゼロパディング: 61 62 00 -> 復号結果 61 62
PKCS#7: 61 62 00 -> 復号結果 61 62 00
OpenSSL は sm4 を CBC として扱います。BouncyCastle と、それを使う Hutool の SmUtil.sm4(key) は、SM4 を ECB と PKCS#7 として扱います。どちらも「普通に SM4 を使っているだけ」の 2 つのシステムでも、モードが食い違うことがあります。
Java: Cipher.getInstance("SM4") -> ECB + PKCS#7
OpenSSL: openssl enc -sm4 -> CBC Java: Cipher.getInstance("SM4/CBC/PKCS5Padding")
OpenSSL: openssl enc -sm4-cbc Java で文字コードを指定せずに getBytes() を呼ぶとプラットフォームの既定値が使われ、中国語版 Windows の JDK 17 以前では GBK になります。すると同じ中国語テキストでも暗号文が変わり、相手側では復号結果が文字化けします。
"国密SM4 test".getBytes() // 中国語版 Windows の JDK <= 17 では GBK -> ECB 暗号文 3188d06cf28db70092f8753cbd5ee518
"国密SM4 test".getBytes(StandardCharsets.UTF_8) -> ECB 暗号文 d830308b0ae4fa7b9a2b5d59f7f65ca5
pay=100.00 が pay=900.00 に変わり、それでも復号は成功します。IV と暗号文に対する MAC を計算し、復号の前に検証してください。たとえば HMAC ジェネレーターを使えます。0123456789abcdeffedcba9876543210 を 16 進数として読めば 16 バイトですが、同じ文字列をテキストとして読むと 32 バイトになり、拒否されます。鍵欄の横にある形式セレクターとバイト数カウンターは、まさにこのミスを防ぐためのものです。 PKCS5Padding も同じパディングです。BouncyCastle はどちらの名前も同じコードパスで処理します。ゼロパディングは、次のブロック境界まで 0x00 を追加するだけです。復号時、Hutool と BouncyCastle は末尾の 0x00 を、本来データの一部だったゼロバイトも含めてすべて取り除きますが、Python の gmssl は 1 バイトしか取り除きません。パディングなしの場合は、入力が 16 バイトブロックの整数倍である必要があります。CTR・CFB・OFB はストリームモードなので、パディングは一切行いません。復号したテキストの末尾に余計な空白、四角い記号、改行が付いているなら、パディングが除去されていません。PKCS#7 のデータをパディングなしで復号すると、値 n のバイトが末尾に n 個残ります(0x09、0x0A、0x0D はタブや改行として表示されます)。出力を Hex に切り替えて、最後のブロックを確認してください。 getBytes() を呼ぶと GBK になります)、そして結果の表記(Base64、小文字の 16 進数、大文字の 16 進数)です。設定をすべて揃えて IV を固定すれば、正しい実装どうしは同一の出力を返します。どちらかのツールを疑うなら、まず両方を GB/T 32907 のテストベクトルで確認してください。 0123456789abcdeffedcba9876543210 にしたとき、1 回の暗号化で 681edf34d206965e86b3e94f536e4246、100 万回の連続暗号化で 595298c7c6fd271f0402f804c33d3f66 にならなければなりません。これらが検証するのはブロック暗号の部分だけなので、次に鍵と IV を固定して CBC でテキストを暗号化し、このページの結果や、ページに表示される OpenSSL コマンドの結果と比較してください。このページのエンジンは、両方のテストベクトルと、5 つすべてのモードでの OpenSSL 3 との照合によってテストされています。 openssl enc -sm4-cbc -K <32 hex digits> -iv <32 hex digits> のように使います。-K は生の鍵を 16 進数で受け取るのでパスワードは介在せず、-nopad で PKCS#7 を無効にでき、-base64 -A で 1 行の Base64 を読み書きします。注意点は 2 つあります。単に -sm4 と書くと CBC を意味すること、そして長さの合わない -K の値は、警告が出るだけで切り詰められるかゼロで埋められることです。このページの OpenSSL パネルは、現在の設定からコマンドを組み立てます。openssl enc にはゼロパディングがないため、その場合は一致しないコマンドを表示する代わりに、その旨を表示します。 SmUtil.sm4(key) は SM4 という名前しか渡さず、BouncyCastle はそれを ECB と PKCS#7(Java でいう PKCS5Padding)で補います。CBC になるのは、SM4/CBC/PKCS5Padding のように完全な文字列を指定した場合だけです。JavaScript では、sm-crypto も既定は ECB で、鍵を 32 桁の 16 進数文字列で受け取り、小文字の 16 進数を出力します。一方 gm-crypt は既定が CBC で、16 文字のテキスト鍵を受け取り、Base64 を出力します。次に平文の文字コードを確認します。Hutool の文字列メソッドは常に UTF-8 を使いますが、中国語版 Windows 上の JDK 17 以前で引数なしの getBytes() を呼ぶと GBK になることがあり、暗号文が変わります。ライブラリの既定値に合わせる でライブラリを選べばこれらを 1 クリックで設定でき、手動で入力することもできます。どれかが不確かでも、まず暗号文を貼り付けてください。自動診断がモード、パディング、IV、エンコーディングの組み合わせを試します。 セキュリティツール
AESをオンラインで復号 — GCM/CBC/CTR、パスフレーズまたは生鍵に対応し、OpenSSLとCryptoJSの「U2FsdGVkX1」形式を自動検出します。処理は100%ブラウザ内で完結し、鍵がこのページから出ることはありません。
セキュリティツール
無料のAESオンライン暗号化ツール — AES-128/192/256、GCM/CBC/CTR、パスフレーズ(PBKDF2)または生鍵に対応。処理は100%ブラウザ内で完結し、外部にアップロードされません。
セキュリティツール
bcrypt パスワードハッシュをオンラインで生成・検証。コスト調整、$2b$/$2a$/$2y$ プレフィックス対応。100% ブラウザ内で処理し、パスワードは一切送信されません。
セキュリティツール
16進数またはテキストを貼り付けるだけで、CRC-8・CRC-16・CRC-32 の全63変種を一度に算出します。手元のチェックサムと一致しない場合は期待値を入力すれば、MODBUS・CCITT-FALSE・XMODEM・KERMIT のどれかを自動で特定。処理はすべてブラウザ内で完結します。
セキュリティツール
無料のオンライン HMAC 生成・検証ツール。Text・Hex・Base64 の鍵で HMAC-SHA256/SHA1/SHA384/SHA512 を計算し、Hex/Base64/Base64URL で出力します。100% ブラウザ内で完結 —— 鍵はページから外に出ません。
セキュリティツール
JWTトークンを無料のJWTデコーダーでオンラインデコード。ヘッダー、ペイロード、署名、有効期限、アルゴリズム、クレームを即座に検査できます。100%ブラウザ動作 — トークンはデバイスから外に出ません。登録不要、追跡なし。