💨

【Go】AES暗号を使用した暗号化、復号化のサンプルコード

2025/02/07に公開

概要

暗号技術入門 第3版に出てきたAESで暗号化、復号化をGoで実装してみた

cryptoパッケージを使用

サンプルコード

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
)

// encryptAES 関数は、指定された平文データを AES-GCM を使用して暗号化し、結果を Base64 エンコードした文字列として返します。
//
// Parameters:
// - plainText: 暗号化するデータ (平文)。
// - key: 暗号化に使用する秘密鍵。長さは 16, 24, 32 バイト(AES-128, AES-192, AES-256 に対応)である必要があります。
//
// Returns:
// - 暗号化されたデータを Base64 エンコードした文字列。
// - エラーが発生した場合にはエラーメッセージ。
func encryptAES(plainText, key string) (string, error) {
	// AES 暗号化モジュールを作成(指定された鍵を使用)。
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", err
	}

	// GCM (Galois/Counter Mode) インスタンスを作成。
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// 暗号化のために Nonce(初期化ベクトル、IV)を生成。Nonce のサイズは GCM 仕様に依存。
	nonce := make([]byte, gcm.NonceSize())
	// 暗号学的に安全な乱数生成器を使用して Nonce を埋める。
	if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	// 平文(plainText)を暗号化し、Nonce をプレフィックスとして付与。
	cipherText := gcm.Seal(nonce, nonce, []byte(plainText), nil)

	// 暗号文を Base64 形式の文字列に変換して返す。
	return base64.StdEncoding.EncodeToString(cipherText), nil
}

// decryptAES 関数は、AES-GCM を使用して暗号文を復号化し、平文データを返します。
//
// Parameters:
// - cipherText: Base64 エンコードされた暗号文。
// - key: 復号化に使用する秘密鍵。暗号化時に使用したものと同じ鍵を指定する必要があります。
//
// Returns:
// - 復号化された平文データ。
// - エラーが発生した場合にはエラーを返す。
func decryptAES(cipherText, key string) (string, error) {
	// AES 復号化モジュールを作成(指定された鍵を使用)。
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		return "", err
	}

	// GCM (Galois/Counter Mode) インスタンスを作成。
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// Base64 形式の暗号文をデコードしてバイトデータに変換する。
	data, err := base64.StdEncoding.DecodeString(cipherText)
	if err != nil {
		return "", err
	}

	// 暗号文の先頭に付加された Nonce を分離。Nonce サイズを確認。
	nonceSize := gcm.NonceSize()
	if len(data) < nonceSize {
		// データが Nonce サイズより小さい場合は不正な暗号文としてエラーを返す。
		return "", errors.New("不正な暗号文です")
	}

	// Nonce(初期化ベクトル)と暗号化されたデータそれぞれに分割。
	nonce, cipherTextBytes := data[:nonceSize], data[nonceSize:]

	// 暗号化データを復号化して平文を取得。
	plainText, err := gcm.Open(nil, nonce, cipherTextBytes, nil)
	if err != nil {
		return "", err
	}

	// 復号化された平文を文字列として返す。
	return string(plainText), nil
}

使用

func main() {
	// keyを32バイトに設定
	aesKey := "aaaaaaaaaabbbbbbbbbbccccccccccdd" 
	plainText := "Hello, World!"

	cipherText, err := encryptAES(plainText, aesKey)
	if err != nil {
		panic(err)
	}

	decryptText, err := decryptAES(cipherText, aesKey)
	if err != nil {
		panic(err)
	}

	fmt.Println("plainText: " + plainText)
	fmt.Println("cipherText: " + cipherText)
	fmt.Println("decryptText: " + decryptText)
}


// 出力
// plainText: hello,world!
// cipherText: rJWxz1xCgZuG9LPBLhz3kgjChsEeYQVXSI4+dEr2ftzlkH1gLRZ3hg==
// decryptText: hello,world!
GitHubで編集を提案

Discussion