Skip to content

SM4

SM4は対称暗号化アルゴリズムで、中国国家密码管理局が発表した商用対称ブロック暗号アルゴリズムであり、16バイトの鍵長をサポートしています。dongleは標準およびストリーミングのSM4暗号化をサポートし、複数のブロックモード、パディングモード、出力形式を提供します。

以下のブロックモードをサポートしています:

  • CBC(Cipher Block Chaining):暗号ブロックチェーンモード、鍵Key、初期化ベクトルIV(16バイト)、パディングモードPaddingの設定が必要
  • ECB(Electronic Codebook):電子コードブックモード、鍵KeyとパディングモードPaddingの設定が必要
  • CTR(Counter):カウンターモード、鍵Keyと初期化ベクトルIV(16バイト)の設定が必要
  • GCM(Galois/Counter Mode):ガロア/カウンターモード、鍵Key、ナンスNonce(1-255バイト)、追加認証データAAD(任意)の設定が必要
  • CFB(Cipher Feedback):暗号フィードバックモード、鍵Keyと初期化ベクトルIV(16バイト)の設定が必要
  • OFB(Output Feedback):出力フィードバックモード、鍵Keyと初期化ベクトルIV(16バイト)の設定が必要

以下のパディングモードをサポートしています:

  • No:パディングなし、平文の長さは16の整数倍である必要があります
  • Zero:ゼロパディング、ブロック境界までゼロバイトでパディング、平文の長さが16の倍数でない場合は0x00バイトでパディング
  • PKCS7:PKCS#7パディング、最も一般的なパディング方式、N個の値がNのバイトでパディング、Nはパディングバイト数
  • PKCS5:PKCS#5パディング、8バイトブロックサイズに適応、N個の値がNのバイトでパディング、Nはパディングバイト数
  • AnsiX923:ANSI X.923パディング、最後のバイトを除きすべて0x00でパディング、最後のバイトはパディングバイト数を示す
  • ISO97971:ISO/IEC 9797-1パディング、最初のバイトは0x80、残りは0x00でパディング
  • ISO10126:ISO/IEC 10126パディング、最後のバイトを除きすべてランダムバイトでパディング、最後のバイトはパディングバイト数を示す
  • ISO78164:ISO/IEC 7816-4パディング、最初のバイトは0x80、残りは0x00でパディング
  • Bit:ビットパディング、平文の末尾に1ビットを追加し、ブロック境界まで0ビットでパディング
  • TBC:末尾ビット補数パディング、最後のデータバイトの最上位ビットに基づいてパディングバイトを決定(MSB=0は0x00、MSB=1は0xFFを使用)

注意CBC/ECBブロックモードのみパディングモードの設定が必要、CBC/CTR/CFB/OFBブロックモードのみ初期化ベクトルの設定が必要

関連モジュールのインポート:

go
import (
    "github.com/dromara/dongle"
    "github.com/dromara/dongle/crypto/cipher"
)

CBC モード

Cipherの作成

go
c := cipher.NewSm4Cipher(cipher.CBC)
// 鍵の設定(16バイト)
c.SetKey([]byte("dongle1234567890"))
// 初期化ベクトルの設定(16バイト)
c.SetIV([]byte("1234567890123456"))
// パディングモードの設定
c.SetPadding(cipher.PKCS7)

データの暗号化

入力データ

go
// 文字列入力
encrypter := dongle.Encrypt.FromString("hello world").BySm4(c)
// バイトスライス入力
encrypter := dongle.Encrypt.FromBytes([]byte("hello world")).BySm4(c)
// ファイルストリーム入力
file, _ := os.Open("test.txt")
encrypter := dongle.Encrypt.FromFile(file).BySm4(c)

// 暗号化エラーのチェック
if encrypter.Error != nil {
    fmt.Printf("暗号化エラー: %v\n", encrypter.Error)
    return
}

出力データ

go
// Hexエンコード文字列を出力
encrypter.ToHexString() // 6cdb55b749358b9fba993fa7c545fce6
// Hexエンコードバイトスライスを出力
encrypter.ToHexBytes()   // []byte("6cdb55b749358b9fba993fa7c545fce6")

// Base64エンコード文字列を出力
encrypter.ToBase64String() // bNtVt0k1i5+6mT+nxUX85g==
// Base64エンコードバイトスライスを出力
encrypter.ToBase64Bytes()   // []byte("bNtVt0k1i5+6mT+nxUX85g==")

// エンコードされていない生の文字列を出力
encrypter.ToRawString()
// エンコードされていない生のバイトスライスを出力
encrypter.ToRawBytes()

データの復号

入力データ

go
// Hexエンコード文字列入力
decrypter := dongle.Decrypt.FromHexString(hexString).BySm4(c)
// Hexエンコードバイトスライス入力
decrypter := dongle.Decrypt.FromHexBytes(hexBytes).BySm4(c)
// Hexエンコードファイル入力
file, _ := os.Open("encrypted.hex")
decrypter := dongle.Decrypt.FromHexFile(file).BySm4(c)

// Base64エンコード文字列入力
decrypter := dongle.Decrypt.FromBase64String(base64String).BySm4(c)
// Base64エンコードバイトスライス入力
decrypter := dongle.Decrypt.FromBase64Bytes(base64Bytes).BySm4(c)
// Base64エンコードファイルストリーム入力
file, _ := os.Open("encrypted.base64")
decrypter := dongle.Decrypt.FromBase64File(file).BySm4(c)

// エンコードされていない生の文字列を入力
decrypter := dongle.Decrypt.FromRawString(rawString).BySm4(c)
// エンコードされていない生のバイトスライスを入力
decrypter := dongle.Decrypt.FromRawBytes(rawBytes).BySm4(c)
// エンコードされていない生のファイルストリームを入力
file, _ := os.Open("encrypted.bin")
decrypter := dongle.Decrypt.FromRawFile(file).BySm4(c)

// 復号エラーのチェック
if decrypter.Error != nil {
    fmt.Printf("復号エラー: %v\n", decrypter.Error)
    return
}

出力データ

go
// 復号化後の文字列を出力
decrypter.ToString() // hello world
// 復号化後のバイトスライスを出力
decrypter.ToBytes() // []byte("hello world")

ECB モード

Cipherの作成

go
c := cipher.NewSm4Cipher(cipher.ECB)
// 鍵の設定(16バイト)
c.SetKey([]byte("dongle1234567890"))
// パディングモードの設定
c.SetPadding(cipher.PKCS7)

データの暗号化

入力データ

go
// 文字列入力
encrypter := dongle.Encrypt.FromString("hello world").BySm4(c)
// バイトスライス入力
encrypter := dongle.Encrypt.FromBytes([]byte("hello world")).BySm4(c)
// ファイルストリーム入力
file, _ := os.Open("test.txt")
encrypter := dongle.Encrypt.FromFile(file).BySm4(c)

// 暗号化エラーのチェック
if encrypter.Error != nil {
    fmt.Printf("暗号化エラー: %v\n", encrypter.Error)
    return
}

出力データ

go
// Hexエンコード文字列を出力
encrypter.ToHexString() // 0eb581f0836f423e088fe68ab8011a2b
// Hexエンコードバイトスライスを出力
encrypter.ToHexBytes()   // []byte("0eb581f0836f423e088fe68ab8011a2b")

// Base64エンコード文字列を出力
encrypter.ToBase64String() // DrWB8INvQj4Ij+aKuAEaKw==
// Base64エンコードバイトスライスを出力
encrypter.ToBase64Bytes()   // []byte("DrWB8INvQj4Ij+aKuAEaKw==")

// エンコードされていない生の文字列を出力
encrypter.ToRawString()
// エンコードされていない生のバイトスライスを出力
encrypter.ToRawBytes()

データの復号

入力データ

go
// Hexエンコード文字列入力
decrypter := dongle.Decrypt.FromHexString(hexString).BySm4(c)
// Hexエンコードバイトスライス入力
decrypter := dongle.Decrypt.FromHexBytes(hexBytes).BySm4(c)
// Hexエンコードファイルストリーム入力
file, _ := os.Open("encrypted.hex")
decrypter := dongle.Decrypt.FromHexFile(file).BySm4(c)

// Base64エンコード文字列入力
decrypter := dongle.Decrypt.FromBase64String(base64String).BySm4(c)
// Base64エンコードバイトスライス入力
decrypter := dongle.Decrypt.FromBase64Bytes(base64Bytes).BySm4(c)
// Base64エンコードファイルストリーム入力
file, _ := os.Open("encrypted.base64")
decrypter := dongle.Decrypt.FromBase64File(file).BySm4(c)

// エンコードされていない生の文字列を入力
decrypter := dongle.Decrypt.FromRawString(rawString).BySm4(c)
// エンコードされていない生のバイトスライスを入力
decrypter := dongle.Decrypt.FromRawBytes(rawBytes).BySm4(c)
// エンコードされていない生のファイルストリームを入力
file, _ := os.Open("encrypted.bin")
decrypter := dongle.Decrypt.FromRawFile(file).BySm4(c)

// 復号エラーのチェック
if decrypter.Error != nil {
    fmt.Printf("復号エラー: %v\n", decrypter.Error)
    return
}

出力データ

go
// 復号化後の文字列を出力
decrypter.ToString() // hello world
// 復号化後のバイトスライスを出力
decrypter.ToBytes() // []byte("hello world")

CTR モード

Cipherの作成

go
c := cipher.NewSm4Cipher(cipher.CTR)
// 鍵の設定(16バイト)
c.SetKey([]byte("dongle1234567890"))
// 初期化ベクトルの設定(16バイト)
c.SetIV([]byte("1234567890123456"))

データの暗号化

入力データ

go
// 文字列入力
encrypter := dongle.Encrypt.FromString("hello world").BySm4(c)
// バイトスライス入力
encrypter := dongle.Encrypt.FromBytes([]byte("hello world")).BySm4(c)
// ファイルストリーム入力
file, _ := os.Open("test.txt")
encrypter := dongle.Encrypt.FromFile(file).BySm4(c)

// 暗号化エラーのチェック
if encrypter.Error != nil {
    fmt.Printf("暗号化エラー: %v\n", encrypter.Error)
    return
}

出力データ

go
// Hexエンコード文字列を出力
encrypter.ToHexString() // 274288a7eac8bb982cb53f
// Hexエンコードバイトスライスを出力
encrypter.ToHexBytes()   // []byte("274288a7eac8bb982cb53f")

// Base64エンコード文字列を出力
encrypter.ToBase64String() // J0KIp+rIu5gstT8=
// Base64エンコードバイトスライスを出力
encrypter.ToBase64Bytes()   // []byte("J0KIp+rIu5gstT8=")

// エンコードされていない生の文字列を出力
encrypter.ToRawString()
// エンコードされていない生のバイトスライスを出力
encrypter.ToRawBytes()

データの復号

入力データ

go
// Hexエンコード文字列入力
decrypter := dongle.Decrypt.FromHexString(hexString).BySm4(c)
// Hexエンコードバイトスライス入力
decrypter := dongle.Decrypt.FromHexBytes(hexBytes).BySm4(c)
// Hexエンコードファイルストリーム入力
file, _ := os.Open("encrypted.hex")
decrypter := dongle.Decrypt.FromHexFile(file).BySm4(c)

// Base64エンコード文字列入力
decrypter := dongle.Decrypt.FromBase64String(base64String).BySm4(c)
// Base64エンコードバイトスライス入力
decrypter := dongle.Decrypt.FromBase64Bytes(base64Bytes).BySm4(c)
// Base64エンコードファイルストリーム入力
file, _ := os.Open("encrypted.base64")
decrypter := dongle.Decrypt.FromBase64File(file).BySm4(c)

// エンコードされていない生の文字列を入力
decrypter := dongle.Decrypt.FromRawString(rawString).BySm4(c)
// エンコードされていない生のバイトスライスを入力
decrypter := dongle.Decrypt.FromRawBytes(rawBytes).BySm4(c)
// エンコードされていない生のファイルストリームを入力
file, _ := os.Open("encrypted.bin")
decrypter := dongle.Decrypt.FromRawFile(file).BySm4(c)

// 復号エラーのチェック
if decrypter.Error != nil {
    fmt.Printf("復号エラー: %v\n", decrypter.Error)
    return
}

出力データ

go
// 復号化後の文字列を出力
decrypter.ToString() // hello world
// 復号化後のバイトスライスを出力
decrypter.ToBytes()  // []byte("hello world")

GCM モード

GCMモードは認証暗号化機能を提供し、追加の認証データ(AAD)をサポートします。

Cipherの作成

go
c := cipher.NewSm4Cipher(cipher.GCM)
// 鍵の設定(16バイト)
c.SetKey([]byte("dongle1234567890"))
// ナンスの設定(1-255バイト)
c.SetNonce([]byte("1234567890"))
// 追加の認証データの設定(任意)
c.SetAAD([]byte("dongle"))

データの暗号化

入力データ

go
// 文字列入力
encrypter := dongle.Encrypt.FromString("hello world").BySm4(c)
// バイトスライス入力
encrypter := dongle.Encrypt.FromBytes([]byte("hello world")).BySm4(c)
// ファイルストリーム入力
file, _ := os.Open("test.txt")
encrypter := dongle.Encrypt.FromFile(file).BySm4(c)

// 暗号化エラーのチェック
if encrypter.Error != nil {
    fmt.Printf("暗号化エラー: %v\n", encrypter.Error)
    return
}

出力データ

go
// Hexエンコード文字列を出力
encrypter.ToHexString() // 248e07df909c174df7ba9ba48e32f8f1ba3f9e1b3344ad8981b50d
// Hexエンコードバイトスライスを出力
encrypter.ToHexBytes()   // []byte("248e07df909c174df7ba9ba48e32f8f1ba3f9e1b3344ad8981b50d")

// Base64エンコード文字列を出力
encrypter.ToBase64String() // JI4H35CcF033upukjjL48bo/nhszRK2JgbUN
// Base64エンコードバイトスライスを出力
encrypter.ToBase64Bytes()   // []byte("JI4H35CcF033upukjjL48bo/nhszRK2JgbUN")

// エンコードされていない生の文字列を出力
encrypter.ToRawString()
// エンコードされていない生のバイトスライスを出力
encrypter.ToRawBytes()

データの復号

入力データ

go
// Hexエンコード文字列入力
decrypter := dongle.Decrypt.FromHexString(hexString).BySm4(c)
// Hexエンコードバイトスライス入力
decrypter := dongle.Decrypt.FromHexBytes(hexBytes).BySm4(c)
// Hexエンコードファイルストリーム入力
file, _ := os.Open("encrypted.hex")
decrypter := dongle.Decrypt.FromHexFile(file).BySm4(c)

// Base64エンコード文字列入力
decrypter := dongle.Decrypt.FromBase64String(base64String).BySm4(c)
// Base64エンコードバイトスライス入力
decrypter := dongle.Decrypt.FromBase64Bytes(base64Bytes).BySm4(c)
// Base64エンコードファイルストリーム入力
file, _ := os.Open("encrypted.base64")
decrypter := dongle.Decrypt.FromBase64File(file).BySm4(c)

// エンコードされていない生の文字列を入力
decrypter := dongle.Decrypt.FromRawString(rawString).BySm4(c)
// エンコードされていない生のバイトスライスを入力
decrypter := dongle.Decrypt.FromRawBytes(rawBytes).BySm4(c)
// エンコードされていない生のファイルストリームを入力
file, _ := os.Open("encrypted.bin")
decrypter := dongle.Decrypt.FromRawFile(file).BySm4(c)

// 復号エラーのチェック
if decrypter.Error != nil {
    fmt.Printf("復号エラー: %v\n", decrypter.Error)
    return
}

出力データ

go
// 復号化後の文字列を出力
decrypter.ToString() // hello world
// 復号化後のバイトスライスを出力
decrypter.ToBytes()  // []byte("hello world")

CFBモード

注意:CFBモードはCFB8実装を使用します。最初の16バイトのデータの場合、CFB8とOFBモードは同じ暗号化結果を生成します。これはGo標準ライブラリCFB8実装の特性であり、バグではありません。

Cipherの作成

go
c := cipher.NewSm4Cipher(cipher.CFB)
// 鍵の設定(16バイト)
c.SetKey([]byte("dongle1234567890"))
// 初期化ベクトルの設定(16バイト)
c.SetIV([]byte("1234567890123456"))

データの暗号化

入力データ

go
// 文字列入力
encrypter := dongle.Encrypt.FromString("hello world").BySm4(c)
// バイトスライス入力
encrypter := dongle.Encrypt.FromBytes([]byte("hello world")).BySm4(c)
// ファイルストリーム入力
file, _ := os.Open("test.txt")
encrypter := dongle.Encrypt.FromFile(file).BySm4(c)

// 暗号化エラーのチェック
if encrypter.Error != nil {
    fmt.Printf("暗号化エラー: %v\n", encrypter.Error)
    return
}

出力データ

go
// Hexエンコード文字列を出力
encrypter.ToHexString() // 274288a7eac8bb982cb53f
// Hexエンコードバイトスライスを出力
encrypter.ToHexBytes()   // []byte("274288a7eac8bb982cb53f")

// Base64エンコード文字列を出力
encrypter.ToBase64String() // J0KIp+rIu5gstT8=
// Base64エンコードバイトスライスを出力
encrypter.ToBase64Bytes()   // []byte("J0KIp+rIu5gstT8=")

// エンコードされていない生の文字列を出力
encrypter.ToRawString()
// エンコードされていない生のバイトスライスを出力
encrypter.ToRawBytes()

データの復号

入力データ

go
// Hexエンコード文字列入力
decrypter := dongle.Decrypt.FromHexString(hexString).BySm4(c)
// Hexエンコードバイトスライス入力
decrypter := dongle.Decrypt.FromHexBytes(hexBytes).BySm4(c)
// Hexエンコードファイルストリーム入力
file, _ := os.Open("encrypted.hex")
decrypter := dongle.Decrypt.FromHexFile(file).BySm4(c)

// Base64エンコード文字列入力
decrypter := dongle.Decrypt.FromBase64String(base64String).BySm4(c)
// Base64エンコードバイトスライス入力
decrypter := dongle.Decrypt.FromBase64Bytes(base64Bytes).BySm4(c)
// Base64エンコードファイルストリーム入力
file, _ := os.Open("encrypted.base64")
decrypter := dongle.Decrypt.FromBase64File(file).BySm4(c)

// エンコードされていない生の文字列を入力
decrypter := dongle.Decrypt.FromRawString(rawString).BySm4(c)
// エンコードされていない生のバイトスライスを入力
decrypter := dongle.Decrypt.FromRawBytes(rawBytes).BySm4(c)
// エンコードされていない生のファイルストリームを入力
file, _ := os.Open("encrypted.bin")
decrypter := dongle.Decrypt.FromRawFile(file).BySm4(c)

// 復号エラーのチェック
if decrypter.Error != nil {
    fmt.Printf("復号エラー: %v\n", decrypter.Error)
    return
}

出力データ

go
// 復号化後の文字列を出力
decrypter.ToString() // hello world
// 復号化後のバイトスライスを出力
decrypter.ToBytes()  // []byte("hello world")

OFBモード

注意:CFBモードはCFB8実装を使用します。最初の16バイトのデータの場合、CFB8とOFBモードは同じ暗号化結果を生成します。これはGo標準ライブラリCFB8実装の特性であり、バグではありません。

Cipherの作成

go
c := cipher.NewSm4Cipher(cipher.OFB)
// 鍵の設定(16バイト)
c.SetKey([]byte("dongle1234567890"))
// 初期化ベクトルの設定(16バイト)
c.SetIV([]byte("1234567890123456"))

データの暗号化

入力データ

go
// 文字列入力
encrypter := dongle.Encrypt.FromString("hello world").BySm4(c)
// バイトスライス入力
encrypter := dongle.Encrypt.FromBytes([]byte("hello world")).BySm4(c)
// ファイルストリーム入力
file, _ := os.Open("test.txt")
encrypter := dongle.Encrypt.FromFile(file).BySm4(c)

// 暗号化エラーのチェック
if encrypter.Error != nil {
    fmt.Printf("暗号化エラー: %v\n", encrypter.Error)
    return
}

出力データ

go
// Hexエンコード文字列を出力
encrypter.ToHexString() // 274288a7eac8bb982cb53f
// Hexエンコードバイトスライスを出力
encrypter.ToHexBytes()   // []byte("274288a7eac8bb982cb53f")

// Base64エンコード文字列を出力
encrypter.ToBase64String() // J0KIp+rIu5gstT8=
// Base64エンコードバイトスライスを出力
encrypter.ToBase64Bytes()   // []byte("J0KIp+rIu5gstT8=")

// エンコードされていない生の文字列を出力
encrypter.ToRawString()
// エンコードされていない生のバイトスライスを出力
encrypter.ToRawBytes()

データの復号

入力データ

go
// Hexエンコード文字列入力
decrypter := dongle.Decrypt.FromHexString(hexString).BySm4(c)
// Hexエンコードバイトスライス入力
decrypter := dongle.Decrypt.FromHexBytes(hexBytes).BySm4(c)
// Hexエンコードファイルストリーム入力
file, _ := os.Open("encrypted.hex")
decrypter := dongle.Decrypt.FromHexFile(file).BySm4(c)

// Base64エンコード文字列入力
decrypter := dongle.Decrypt.FromBase64String(base64String).BySm4(c)
// Base64エンコードバイトスライス入力
decrypter := dongle.Decrypt.FromBase64Bytes(base64Bytes).BySm4(c)
// Base64エンコードファイルストリーム入力
file, _ := os.Open("encrypted.base64")
decrypter := dongle.Decrypt.FromBase64File(file).BySm4(c)

// エンコードされていない生の文字列を入力
decrypter := dongle.Decrypt.FromRawString(rawString).BySm4(c)
// エンコードされていない生のバイトスライスを入力
decrypter := dongle.Decrypt.FromRawBytes(rawBytes).BySm4(c)
// エンコードされていない生のファイルストリームを入力
file, _ := os.Open("encrypted.bin")
decrypter := dongle.Decrypt.FromRawFile(file).BySm4(c)

// 復号エラーのチェック
if decrypter.Error != nil {
    fmt.Printf("復号エラー: %v\n", decrypter.Error)
    return
}

出力データ

go
// 復号化後の文字列を出力
decrypter.ToString() // hello world
// 復号化後のバイトスライスを出力
decrypter.ToBytes()  // []byte("hello world")

MITライセンスに基づいて公開されており、許可なく複製することは禁止されています