LoginSignup
16
8

More than 1 year has passed since last update.

.NETで暗号化

Last updated at Posted at 2022-11-23

はじめに

最近ならAES256/GCMを使っておけば大丈夫な気がするので、その使い方。

.NETの場合、.NET Framework では最新の4.8でもAesGcmが無いので使えないことに注意、.NET Frameworkでなければならない場合はAES256/CBCとかにするのかな。CBCではパディングオラクル攻撃に注意。パディングのエラーをそれとわかるように通知してはいけない。
.NET Core 3.0 以降なら大丈夫、もちろん .NET 5, 6, 7もOK。

Javaで暗号化、.NETで復号化とかしようとすると、tagが別になっているのでうまくいかない、注意。
Java版の話はこちら⇨ Javaで暗号化

暗号鍵

Javaと違って単なるbyte配列で良い。パスワードから作る場合はSHA256で。

using System.Text;
using System.Security.Cryptography;
    .
    .
    .
    public byte[] generateRandomKey()
    {
        byte[] key = new byte[32];
        RandomNumberGenerator.Fill(key);
        return key;
    }

    public byte[] getKeyFromPassword(string pass)
    {
        SHA256 sha = SHA256.Create();
        byte[] ret = sha.ComputeHash(Encoding.UTF8.GetBytes(pass));
        return ret;
    }

IVとtag

GCMでは改ざんを検知するために暗号文と同時にtagが出力される。Javaでは暗号文と一緒のbyte配列になって出力されたが、.NETでは別に領域を用意しておく必要がある。
IVをnonceから作るのはJavaと同じ。
バッファサイズは一応定数定義があるので、それを使っている。
nonce, tag, 暗号文は復号側にそのまま送って構わない。

using System.Security.Cryptography;
    .
    .
    .
    public byte[] generateNonce()
    {
        byte[] nonce = new byte[AesGcm.NonceByteSizes.MaxSize];
        return nonce;
    }

    public byte[] getTagBuffer()
    {
        byte[] tag = new byte[AesGcm.TagByteSizes.MaxSize];
        return tag;
    }

AAD

AADについてもJavaと同じで、任意のbyte配列を使う。
サンプルでは「AADは追加認証データ、中身はなんでも良いが64kBytes以内にする」の文字列をUTF-8のバイト列として使っている。

暗号化

AesGcmを使って暗号化する。暗号文とtagが別々になっていて、tag用の領域は先に確保しておく必要がある。

using System.Security.Cryptography;
    .
    .
    .
    public byte[] encrypt(byte[] src, byte[] key, byte[] nonce, byte[] tag_dest)
    {
        AesGcm aes = new AesGcm(key);
        byte[] dest_buf = new byte[src.Length];
        byte[] aad = Encoding.UTF8.GetBytes("AADは追加認証データ、中身はなんでも良いが64kBytes以内にする");
        aes.Encrypt(nonce, src, dest_buf, tag_dest, aad);
        return dest_buf;
    }

復号化

暗号化とほぼ変わらないが、tagは入力になる。

using System.Security.Cryptography;
    .
    .
    .
    public byte[] decrypt(byte[] src, byte[] key, byte[] nonce, byte[] tag_src)
    {
        AesGcm aes = new AesGcm(key);
        byte[] dest_buf = new byte[src.Length];
        byte[] aad = Encoding.UTF8.GetBytes("AADは追加認証データ、中身はなんでも良いが64kBytes以内にする");
        aes.Decrypt(nonce, src, tag_src, dest_buf, aad);
        return dest_buf;
    }

まとめ

実際に使う場合はこんな感じ。

    // 暗号化
    byte[] key = getKeyFromPassword("P@ssW0rd");
    byte[] nonce = generateNonce();
    byte[] tag = getTagBuffer();
    byte[] encdata = encrypt(srcdata, key, nonce, tag);

    // 復号化
    byte[] key = getKeyFromPassword("P@ssW0rd");
    byte[] nonce = <送られてきたnonce>;
    byte[] tag = <送られてきたtag>;
    byte[] decdata = decrypt(encdata, key, nonce, tag);
16
8
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
16
8