Java/JavaScript/C#で暗号化する

各言語で暗号化。
やってみると、暗号化後の文字列が各言語で違ってしまったりして、意外とハマったりします。
ここでは、Java/JavaScript/C#を取り上げてみます。

# 暗号化
## Java
まずは、Java。

```java:Crypto.java
import java.nio.charset.StandardCharsets;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.util.Base64;

public final class Crypto {

    private static final String KEY = "1234567890abcdef";
    private static final String IV = "abcdef1234567890";

    private Crypto() {
    }

    private static Cipher createCipher(int mode) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec key = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec iv = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
        cipher.init(mode, key, iv);
        return cipher;
    }

    public static String encrypt(String text) {
        try {
            Cipher cipher = createCipher(Cipher.ENCRYPT_MODE);
            Base64.Encoder encoder = Base64.getEncoder();
            return encoder.encodeToString(cipher.doFinal(text.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String decrypt(String text) {
        try {
            Cipher cipher = createCipher(Cipher.DECRYPT_MODE);
            Base64.Decoder decoder = Base64.getDecoder();
            return new String(cipher.doFinal(decoder.decode(text)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
```

## JavaScript
次にJavaScript。実行環境はNode.jsです。

```javascript:Crypto.js
const crypto = require('crypto')

const KEY = '1234567890abcdef'
const IV = 'abcdef1234567890'

function createCipher(mode) {
    return crypto[mode]('aes-128-cbc', KEY, IV)
}

function encrypt(text) {
    const cipher = createCipher('createCipheriv')
    const encrypted = cipher.update(text);
    return Buffer.concat([encrypted, cipher.final()]).toString('base64')
}

function decrypt(text) {
    const buf = Buffer.from(text, 'base64')
    const cipher = createCipher('createDecipheriv')
    const decrypted = cipher.update(buf);
    return Buffer.concat([decrypted, cipher.final()]).toString('utf-8')
}
```

## C# 
最後にC#。

```c#:Crypto.cs
using System;
using System.Security.Cryptography;
using System.Text;

public sealed class Crypto
{
    private const string KEY = "1234567890abcdef";
    private const string IV = "abcdef1234567890";

    private Crypto()
    {
    }

    private static AesManaged CreateAesManaged()
    {
        AesManaged aes = new AesManaged();
        aes.KeySize = 256;
        aes.BlockSize = 128;
        aes.Mode = CipherMode.CBC;
        aes.IV = Encoding.UTF8.GetBytes(IV);
        aes.Key = Encoding.UTF8.GetBytes(KEY);
        aes.Padding = PaddingMode.PKCS7;
        return aes;
    }

    public static string Encrypt(string text)
    {
        AesManaged aes = CreateAesManaged();
        byte[] byteText = Encoding.UTF8.GetBytes(text);
        byte[] encryptText = aes.CreateEncryptor().TransformFinalBlock(byteText, 0, byteText.Length);
        return Convert.ToBase64String(encryptText);
    }

    public static string Decrypt(string text)
    {
        AesManaged aes = CreateAesManaged();
        byte[] src = System.Convert.FromBase64String(text);
        byte[] dest = aes.CreateDecryptor().TransformFinalBlock(src, 0, src.Length);
        return Encoding.UTF8.GetString(dest);
    }
}
```

# 結果
暗号化（<code>encrypt</code>）すると、以下の結果になります。

* ""（空文字）=> 0e8Yyuobp55/giEyC01lbg==
* alz1590-'$ => cMgaJ1X/cVENp+rnMo/8Kw==
* あむんアムンｱﾑﾝ亜無漚錡𠀋𪚲 => jXw9bzISBZsndhcrJx/gJU7ltBzSp34xn6CL3xBbNE2yC0FhQBisP27WOXan/W2o

復号（<code>decrypt</code>）すると、元の文字列が得られます。

# 補足

* <code>IV</code>は初期化ベクトルです。同じデータであっても違う暗号文にするための文字列です。
* <code>KEY</code>/<code>IV</code>は長さに決まりがあるので注意。