SM4 키 길이
16바이트 정확히 128비트, 즉 16바이트이며 hex 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 |
| 1,000,000회 암호화한 암호문 | 595298c7c6fd271f0402f804c33d3f66 |
암호 도구를 만드는 개발자가 작성하고 검토했습니다. 이 페이지에 인용한 모든 암호문과 바이트 수는 도구의 엔진으로 계산했으며 테스트로 확인했습니다.
16바이트 정확히 128비트, 즉 16바이트이며 hex 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-box와 선형 변환에 통과시킨 뒤 네 번째 워드에 합칩니다. 32개의 라운드 키는 두 종류의 고정 상수를 사용해 키로부터 유도되며, 복호화는 라운드 키를 역순으로 적용하는 같은 연산입니다.
블록 암호 자체는 정확히 16바이트만 처리할 수 있으므로, 실제 데이터는 항상 운영 모드를 거칩니다. 이 도구는 고전적인 다섯 가지 모드를 지원합니다. ECB와 CBC는 블록 단위로 동작해 패딩이 필요하고, CTR, CFB, OFB는 SM4를 스트림 암호처럼 동작하게 해 패딩이 전혀 필요 없습니다. 복호화 실패는 대부분 SM4 자체와는 무관합니다. 양쪽이 모드, 패딩, IV, 텍스트 인코딩, 키 문자열을 바이트로 바꾸는 방식을 서로 다르게 가정한 것이 원인이며, 그냥 "SM4"라고만 썼을 때의 의미조차 라이브러리마다 다릅니다.
브라우저에 내장된 Web Crypto API는 SM4를 지원하지 않으므로, 이 페이지는 자체 구현을 싣고 로컬에서 실행합니다. 이 구현은 GB/T 32907의 테스트 벡터 두 개로 테스트되었고, 모든 모드에서 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의 기본값을 적용합니다. 이 라이브러리들은 그냥 "SM4"가 ECB인지 CBC인지조차 서로 다르게 해석합니다.
ECB, CBC, CTR, CFB, OFB 모드와 PKCS#7, 제로 패딩, 패딩 없음을 지원합니다. 평문은 UTF-8 또는 GBK를 쓸 수 있으며, GBK는 오래된 Java 코드가 중국어 Windows에서 만들어 내는 인코딩입니다. GCM은 지원하지 않습니다.
클릭 한 번으로 16바이트 무작위 키나 IV를 생성하거나, 코드에 적힌 형식 그대로 입력하세요. 실시간 바이트 카운터로 정확히 16바이트인지 먼저 확인한 다음 다른 원인을 찾을 수 있습니다.
부록 A의 두 결과를 표로 보여 주고 클릭 한 번으로 불러올 수 있어, 어떤 SM4 구현이든 표준과 대조해 검증할 수 있습니다.
모든 결과에 그 결과를 재현하는 openssl enc 명령이 함께 표시되므로, 터미널에서 직접 확인하거나 동료에게 전달할 수 있습니다.
SM4 엔진은 로컬에서 실행됩니다. 키와 데이터는 페이지를 벗어나지 않으며, 오프라인에서도 계속 동작합니다.
openssl enc)-sm4 = CBC -sm4는 -sm4-cbc의 별칭입니다. -K와 -iv는 hex를 받고, -nopad를 주지 않는 한 PKCS#7이 켜져 있으며, -base64 -A를 붙이지 않으면 원시 바이트를 출력합니다. 길이가 틀린 -K는 경고만 표시된 채 잘리거나 0으로 채워집니다.
SmUtil.sm4(key)Hutool은 SM4라는 이름만 넘기고, BouncyCastle은 이를 ECB와 PKCS#7(JCE 이름은 PKCS5Padding)로 실행합니다. 문자열 메서드는 UTF-8을 쓰고 encryptHex는 소문자 hex를 출력합니다. 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자리 hex 문자열로 받으며 소문자 hex를 반환합니다. mode: 'cbc'일 때만 모드가 바뀌고, 그 밖의 값은 조용히 ECB로 남습니다. sm-crypto-v2도 동작은 같지만, CBC에 iv를 주지 않으면 전부 0인 IV를 사용합니다.
기본값은 CBC이며, 키와 IV를 16자 UTF-8 문자열로 받고 Base64를 반환합니다. 바이트가 유효한 UTF-8이 아닌 키는 아예 넘길 수 없습니다.
CryptSM4crypt_ecb와 crypt_cbc 중 무엇을 호출하느냐로 모드가 정해집니다. set_key는 처음 16바이트만 읽으므로 더 긴 키는 조용히 잘리고, 키가 틀리면 대개 오류 대신 빈 바이트열을 반환합니다.
sm4Sm4Cbc는 SetIV를 호출하기 전까지 전부 0으로 남는 패키지 수준 IV를 사용하고, CFB와 OFB에서도 PKCS#7로 패딩하며, 언패딩 오류를 버립니다. 그래서 키가 틀려도 오류 없이 nil을 반환합니다.
키 0123456789abcdeffedcba9876543210, 평문(hex) 0123456789abcdeffedcba9876543210
681edf34d206965e86b3e94f536e4246
GB/T 32907-2016 부록 A의 예제 1입니다. 키와 평문이 같은 128비트 값이며, 한 번 암호화하면 681edf34d206965e86b3e94f536e4246이 됩니다. 그 출력을 다시 암호화하는 과정을 총 100만 번 반복하면 595298c7c6fd271f0402f804c33d3f66이 나옵니다. 두 값 모두 이 페이지의 테스트 벡터 표에 실려 있으며, 지금 사용 중인 것과 같은 엔진으로 계산한 값입니다. GB/T 32907 테스트 벡터 버튼을 누르면 첫 번째 벡터가 로드됩니다.
키 0123456789abcdeffedcba9876543210, IV fedcba98765432100123456789abcdef, 평문: SM4 interop test: order 20260911-0042
Wi6BuLpov8RndEfedUyLXFvDRnLMoo7T6O04Q83IzKDuDvPQ2S5clq+cEQXMvy/y
평문은 UTF-8로 37바이트입니다. PKCS#7 패딩을 붙이면 16바이트 블록 3개인 48바이트가 되고, 이를 Base64로 쓰면 64자가 됩니다. 예시 불러오기 버튼을 누르면 정확히 이 값들이 채워지며, OpenSSL 패널에는 터미널에서 같은 Base64 문자열을 재현하는 명령이 표시됩니다.
위의 암호문을 복호화하면서 IV로 00000000000000000000000000000000 사용
알아볼 수 없는 16바이트 + ": order 20260911-0042"
CBC는 IV를 첫 블록에만 섞고 PKCS#7 패딩은 마지막 블록에 있으므로, 패딩 검사는 그대로 통과하고 OpenSSL도 오류를 내지 않습니다. 이 페이지는 첫 블록을 읽을 수 없다는 점을 감지해, 키와 모드는 맞고 IV가 문제라는 것, 혹은 암호문의 처음 16바이트 자체가 IV라는 것을 알려 줍니다.
상대 쪽 라이브러리를 안다면 라이브러리 기본값 맞추기에서 고르세요. 모른다면 암호화하기 또는 복호화하기를 선택하고 모드와 패딩을 맞춥니다. 스트림 모드(CTR, CFB, OFB)에는 패딩이 없으므로 패딩 선택기가 비활성화됩니다.
둘 다 정확히 16바이트입니다. 문자열이 쓰인 형식(hex, 텍스트, Base64)을 고르고 바이트 카운터가 초록색으로 바뀌는지 확인하세요. 무작위 생성 버튼을 누르면 새 값이 생성됩니다.
암호화할 때는 텍스트(UTF-8 또는 GBK)를 입력하거나 hex 바이트를 붙여넣습니다. 복호화할 때는 암호문을 붙여넣고 Base64인지 hex인지 지정합니다. 결과는 입력하는 즉시 갱신됩니다.
출력을 복사하거나, '이 암호문 복호화' 버튼을 눌러 같은 키와 IV를 유지한 채 복호화 탭으로 넘깁니다. OpenSSL 패널에는 같은 결과를 재현하는 명령이 표시됩니다.
진단 결과에는 입력값이 읽을 수 있는 텍스트로 복호화되는 설정이 나열됩니다. 클릭 한 번으로 적용하거나, 처음 16바이트만 실패했다면 안내 문구를 읽어 보세요. 이 경우 원인은 IV입니다.
32자짜리 hex 문자열은 hex로 디코딩할 때만 16바이트입니다. 텍스트로 읽으면 32바이트가 되어 SM4에서 거부되고, 키를 조용히 자르거나 채우는 코드에서는 아예 다른 키가 됩니다.
키 (텍스트): 0123456789abcdeffedcba9876543210 -> 32바이트, 거부됨
키 (hex): 0123456789abcdeffedcba9876543210 -> 16바이트
양쪽은 같은 모드를 써야 합니다. CBC 암호문을 ECB로 복호화하면 모든 블록이 깨지고, 대개 마지막의 패딩 검사에서도 실패합니다.
encrypt: SM4/CBC/PKCS5Padding decrypt: SM4/ECB/PKCS5Padding -> bad decrypt
encrypt: SM4/CBC/PKCS5Padding decrypt: SM4/CBC/PKCS5Padding, 같은 IV
CBC에서는 IV가 틀려도 오류가 나지 않습니다. 처음 16바이트만 깨지고 나머지는 정상적으로 복호화됩니다. 평문 앞부분만 깨졌다면 양쪽의 IV를 비교하세요.
복호화 IV 00000000000000000000000000000000 -> 알아볼 수 없는 16바이트 + ": order 20260911-0042"
복호화 IV fedcba98765432100123456789abcdef -> "SM4 interop test: order 20260911-0042"
Base64와 hex는 같은 바이트를 적는 두 가지 방식입니다. 한쪽을 다른 쪽으로 읽으면 블록 암호에 처음부터 잘못된 입력이 들어갑니다.
Wi6BuLpov8RndEfedUyLXFvDRnLMoo7T6O04Q83IzKDuDvPQ2S5clq+cEQXMvy/y hex로 읽음 -> 유효하지 않음
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를 쓰는" 두 시스템이라도 모드가 서로 다를 수 있습니다.
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으로 바뀌고, 복호화는 여전히 성공합니다. HMAC 생성기 등으로 IV와 암호문에 대한 MAC을 계산하고, 복호화하기 전에 검증하세요.0123456789abcdeffedcba9876543210을 hex로 읽으면 16바이트지만, 같은 문자열을 텍스트로 읽으면 32바이트가 되어 거부됩니다. 키 입력란 옆의 형식 선택기와 바이트 카운터가 바로 이런 실수를 잡아내기 위해 있습니다. PKCS5Padding도 같은 패딩이며, BouncyCastle은 두 이름을 같은 코드 경로로 처리합니다. 제로 패딩은 다음 블록 경계까지만 0x00을 채웁니다. 복호화할 때 Hutool과 BouncyCastle은 끝에 붙은 0x00을 원래 데이터의 일부였던 0x00 바이트까지 전부 제거하지만, Python의 gmssl은 하나만 제거합니다. 패딩 없음은 입력 길이가 16바이트 블록의 정수 배여야 합니다. CTR, CFB, OFB는 스트림 모드라서 패딩을 전혀 쓰지 않습니다. 복호화한 텍스트 끝에 알 수 없는 공백, 네모 문자, 줄바꿈이 남아 있다면 패딩이 제거되지 않은 것입니다. PKCS#7로 패딩한 데이터를 패딩 없음으로 복호화하면 끝에 값이 n인 바이트가 n개 남습니다(0x09, 0x0A, 0x0D는 탭과 줄바꿈으로 보입니다). 출력을 Hex로 바꿔 마지막 블록을 확인하세요. getBytes()를 호출하면 GBK), 결과를 어떻게 출력했는지(Base64, 소문자 hex, 대문자 hex)를 비교하세요. 설정이 같고 IV가 고정되어 있다면 올바른 구현 두 개는 똑같은 결과를 냅니다. 어느 한 도구가 의심스럽다면 먼저 두 도구를 모두 GB/T 32907 테스트 벡터로 검증하세요. 0123456789abcdeffedcba9876543210일 때, 1회 암호화하면 681edf34d206965e86b3e94f536e4246, 100만 회 연쇄 암호화하면 595298c7c6fd271f0402f804c33d3f66이 나와야 합니다. 이 벡터는 블록 암호 자체만 검증하므로, 다음으로 고정된 키와 IV로 텍스트를 CBC 모드로 암호화해 이 페이지의 결과나 이 페이지가 보여 주는 OpenSSL 명령의 결과와 비교하세요. 이 페이지의 엔진은 두 벡터로 테스트되었고, 다섯 가지 모드 모두에서 OpenSSL 3과 교차 검증되었습니다. openssl enc -sm4-cbc -K <32 hex digits> -iv <32 hex digits> 형식으로 사용합니다. -K는 hex로 된 원시 키를 받으므로 비밀번호가 개입하지 않고, -nopad는 PKCS#7을 끄며, -base64 -A는 한 줄짜리 Base64를 읽거나 씁니다. 두 가지를 주의하세요. 그냥 -sm4라고 쓰면 CBC를 뜻하고, 길이가 틀린 -K 값은 경고만 표시된 채 잘리거나 0으로 채워집니다. 이 페이지의 OpenSSL 패널은 현재 설정으로 명령을 구성합니다. openssl enc에는 제로 패딩이 없으므로, 그 경우 패널은 결과가 일치하지 않을 명령을 출력하는 대신 그 사실을 알려 줍니다. SmUtil.sm4(key)는 SM4라는 이름만 넘기고, BouncyCastle은 나머지를 ECB와 PKCS#7(Java의 PKCS5Padding)로 채웁니다. SM4/CBC/PKCS5Padding처럼 전체 문자열을 지정해야만 CBC가 됩니다. JavaScript의 sm-crypto 역시 기본값이 ECB이고, 키를 32자리 hex 문자열로 받으며 소문자 hex를 출력합니다. 반면 gm-crypt는 기본값이 CBC이고, 16자 텍스트 키를 받으며 Base64를 출력합니다. 그다음 평문의 문자 집합을 확인하세요. Hutool의 문자열 메서드는 항상 UTF-8을 쓰지만, 중국어 Windows의 JDK 17 이하에서 인자 없는 getBytes()는 GBK를 뜻할 수 있고, 그러면 암호문이 달라집니다. 라이브러리 기본값 맞추기에서 라이브러리를 고르면 이 설정이 한 번에 지정되며, 직접 입력해도 됩니다. 확실하지 않은 항목이 있다면 일단 암호문을 붙여넣으세요. 자동 진단이 모드, 패딩, IV, 인코딩의 조합을 시도합니다. 보안 도구
온라인 AES 복호화 — GCM/CBC/CTR, 암호 문구 또는 원시 키, OpenSSL·CryptoJS "U2FsdGVkX1" 형식 자동 인식. 브라우저에서만 실행되며 키는 유출되지 않습니다.
보안 도구
무료 온라인 AES 암호화 도구 — AES-128/192/256, GCM/CBC/CTR, 암호 문구(PBKDF2) 또는 원시 키. 브라우저에서만 실행되고 서버 업로드는 없습니다.
보안 도구
온라인으로 bcrypt 비밀번호 해시를 생성·검증하세요 — 조절 가능한 비용 인자, $2b$/$2a$/$2y$ 접두사 지원. 100% 브라우저에서 실행, 비밀번호는 업로드되지 않습니다.
보안 도구
16진수나 텍스트에서 CRC-8·CRC-16·CRC-32 변형 63개를 계산하는 온라인 도구. 맞지 않는 체크섬을 역조회 칸에 넣으면 MODBUS 등 어느 변형인지 알려 줍니다.
보안 도구
무료 온라인 HMAC 생성·검증 도구. Text/Hex/Base64 키로 HMAC-SHA256/SHA1/SHA384/SHA512를 Hex/Base64/Base64URL로 출력. 100% 브라우저 실행, 키 유출 없음.
보안 도구
무료 JWT 디코더로 JWT 토큰을 온라인에서 즉시 디코딩. 헤더, 페이로드, 서명, 만료, 클레임 확인. 100% 브라우저 기반 — 토큰이 기기를 떠나지 않음. 가입·추적 없음.