28
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

HRBrainAdvent Calendar 2022

Day 9

Goでエンベロープ暗号化してみた

Last updated at Posted at 2022-12-08

この記事はHRBrain Advent Calendar 2022 カレンダー2の9日目の記事です。

はじめに

株式会社HRBrainでエンジニアをやっている深谷です。
この記事ではGoでエンベロープ暗号化を実装したことについて書いていこうと思います。

エンベロープ暗号化とは

エンベロープ暗号化とは、暗号化された鍵、つまりデータ暗号鍵とルート鍵を使用して機密データを保護するプロセスのことです。

簡単に説明すると

  • コンテンツ
  • コンテンツを暗号化する鍵
  • その鍵を暗号化する鍵

以上を使用して機密データを安全に管理しましょうってことです。

一般的な暗号化方式では平文などのデータを様々な暗号化形式によって暗号化します。
しかしデータと暗号化したときの鍵があればもともとのデータが見えてしまいます。
エンベロープ暗号化では暗号化した鍵をさらに別の鍵で暗号化します。
なので一般的な暗号化方式より安全にデータを扱うことができます。

今回採用したもの

暗号化形式: XChaCha20-Poly1305
ChaCha20-Poly1305の拡張版。
暗号化にChaCha20とPoly1305を使用している。
ChaCha20は、AESよりも安全性が高いとされる暗号化アルゴリズムです。Poly1305は、暗号文の改ざんを防ぐためのメッセージ認証符号。

データ暗号鍵: CEK
CEK(Content Encrypting Key)は、暗号化されたデータを復号するための鍵。
暗号化されたデータを復号して、元のデータを復元することができる。

鍵暗号鍵: KEK
KEK(Key Encrypting Key)は、暗号化された鍵を復号するための鍵。
KEKは、暗号化された鍵を復号するために必要な鍵。

実装

1: コンテンツを暗号化するためのCEKを生成。

const keySize = 32
func generateCEK() ([]byte, error) {
	key := make([]byte, keySize)
	if _, err := rand.Read(key); err != nil {
		// エラー処理
	}
	return key, nil
}

2: CEKを暗号化するためのKEKを生成。
ほぼCEKと処理が同じなので省略。
KEKの強度を上げる場合は、saltを用意してargon2を利用するといいかもです。

argon2
2015年7月に開催されたパスワードハッシュ競技会で優勝した鍵導出関数で、パスワードとsaltから暗号化キーを導出するために使用できます。

3: コンテンツをCEKとKEKで暗号化する関数を用意

func encryptByKey(text []byte, key []byte) ([]byte, error) {
	aead, err := chacha20poly1305.NewX(key)
	if err != nil {
		// エラー処理
	}
	nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(text)+aead.Overhead())
	if _, err := rand.Read(nonce); err != nil {
    	// エラー処理
	}
	encryptedMsg := aead.Seal(nonce, nonce, text, nil)
	return encryptedMsg, nil
}

4: encryptByKeyを適宜呼び出し、暗号化する

func Encrypt(contents []byte) ([]byte, []byte, error) {
	KEK, err := getKEK()
	if err != nil {
		// エラー処理
	}
	CEK, err := generateCEK()
	if err != nil {
		// エラー処理
	}
    // コンテンツをCEKで暗号化
	encryptedData, err := encryptByKey(contents, CEK)
	if err != nil {
		// エラー処理
	}
    // CEKをKEKで暗号化
	encryptedKey, err := encryptByKey(CEK, KEK)
	if err != nil {
		// エラー処理
	}
	return encryptedData, encryptedKey, nil
}

復号化について、詳細は省きますが

  1. KEKを再生成
  2. 暗号化済みのCEKをKEKを使用して復号
  3. 復号したCEKを使用してコンテンツを復号

以上の流れで復号化することが可能ですのでぜひやってみてください。

まとめ

今回はGoでエンベロープ暗号化する一連の流れを紹介しました。

ということで、そんな弊社に興味を持った方がいればぜひ下記ページからご応募ください!

28
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?