kotlinで暗号化、復号化

# 暗号化
## 秘密鍵の生成
SecretKeySpecクラスを使用して秘密鍵を作成します。

```kotlin
val key = SecretKeySpec(["鍵として使用するbyte配列"], "AES")
// ex) val key = SecretKeySpec("0123456789ABCDEF".toByteArray(), "AES")
```

## Cipherクラスのオブジェクトを作成
Cipher.getInstanceで暗号化アルゴリズムを指定してCipherクラスのオブジェクトを作成します。
引数には `暗号化アルゴリズム/動作モード/パディング` の書式で指定します。
詳しくは各ドキュメントを参照してください。
[developer.android.com](https://developer.android.com/reference/javax/crypto/Cipher)
[docs.oracle.com](https://docs.oracle.com/javase/jp/8/docs/api/javax/crypto/Cipher.html)

```kotlin
val cipher = Cipher.getInstance("algorithm/mode/padding")
// ex) val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
```

## 秘密鍵の初期化
Cipher.initでCipher.ENCRYPT_MODEを指定して秘密鍵を初期化します。

```kotlin
cipher.init(Cipher.ENCRYPT_MODE, key)
```

## 読み込みと書き出し
暗号化したいファイルの読み込んで暗号化し、そのデータを書き出します。

```kotlin
val fis = FileInputStream("./before.json")
val fos = FileOutputStream("./encrypto.byte")
val cos = CipherOutputStream(fos, cipher)
val a = ByteArray(8)
var i = fis.read(a)
while (i != -1) {
  cos.write(a, 0, i)
  i = fis.read(a)
}
cos.flush()
cos.close()
```

## IVをつける
今回はモードをCBCに指定したので、暗号化する際にIV（initialization vector）というものが自動的に作られ使われます。
このIVは復号化の際に必要となるため、暗号化したデータの先頭にIVをつけます。

```kotlin
fos.write(cipher.getIV())
```

## ソースコード全文

```encrypto.kt

import java.io.FileInputStream
import java.io.FileOutputStream

import javax.crypto.Cipher
import javax.crypto.CipherInputStream
import javax.crypto.CipherOutputStream
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec


fun main(args: Array<String>) {
  val fis = FileInputStream("./before.json")
  val key = SecretKeySpec("0123456789ABCDEF".toByteArray(), "AES")
  val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
  cipher.init(Cipher.ENCRYPT_MODE, key)
  val fos = FileOutputStream("./encrypto.byte")
  val cos = CipherOutputStream(fos, cipher)
  fos.write(cipher.getIV())
  val a = ByteArray(8)
  var i = fis.read(a)
  while (i != -1) {
    cos.write(a, 0, i)
    i = fis.read(a)
  }
  cos.flush()
  cos.close()
}
```
# 復号化
## 秘密鍵の生成
SecretKeySpecクラスを使用して秘密鍵を作成します。

```kotlin
val key = SecretKeySpec(["鍵として使用するbyte配列"], "AES")
// ex) val key = SecretKeySpec("0123456789ABCDEF".toByteArray(), "AES")
```

## Cipherクラスのオブジェクトを作成
Cipher.getInstanceで暗号化アルゴリズムを指定してCipherクラスのオブジェクトを作成します。
引数には `暗号化アルゴリズム/動作モード/パディング` の書式で指定します。

```kotlin
val cipher = Cipher.getInstance("algorithm/mode/padding")
// ex) val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
```

## IVの読み込み
IV用のbyte配列を用意して、ファイルのIV部分（先頭16byte）を格納します。

```kotlin
val iv = ByteArray(16)
fis.read(iv)
```

## IvParameterSpecの生成
読み込んだIVからIvParameterSpecを生成します。

```kotlin
val ivspec = IvParameterSpec(iv)
```

## 秘密鍵の初期化
Cipher.initでCipher.DECRYPT_MODEを指定して秘密鍵を初期化します。
暗号化のときとは異なり、第三引数にIvParameterSpecを指定します。

```kotlin
cipher.init(Cipher.DECRYPT_MODE, key, ivspec)
```

## 読み込みと書き出し
ファイルを読み込んで復号化して、そのデータを書き出します。

```kotlin
val fis = FileInputStream("./encrypto.byte")
val cis = CipherInputStream(fis, cipher)
val reader = cis.bufferedReader()
val file = File("./after.json")
val fw = FileWriter(file)
var line: String? = reader.readLine()
while (line != null) {
  fw.write(line)
  line = reader.readLine()
}
reader.close()
fw.close()
```

## ソースコード全文

```decrypto.kt
import java.io.FileInputStream
import java.io.File
import java.io.FileWriter

import javax.crypto.Cipher
import javax.crypto.CipherInputStream
import javax.crypto.CipherOutputStream
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec


fun main(args: Array<String>) {
  val fis = FileInputStream("./encrypto.byte")
  val key = SecretKeySpec("0123456789ABCDEF".toByteArray(), "AES")
  val iv = ByteArray(16)
  fis.read(iv)
  val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
  val ivspec = IvParameterSpec(iv)
  cipher.init(Cipher.DECRYPT_MODE, key, ivspec)
  val cis = CipherInputStream(fis, cipher)
  val reader = cis.bufferedReader()

  val file = File("./after.json")
  val fw = FileWriter(file)
  var line: String? = reader.readLine()
  while (line != null) {
    fw.write(line)
    line = reader.readLine()
  }
  reader.close()
  fw.close()
}
```

# コマンドラインでの実行
## コンパイル
encripto.kt、decrypto.ktをそれぞれkotlincコマンドでコンパイルしてjarファイルを作成します。

```
kotlinc encrypto.kt -include-runtime -d encrypto.jar
```

## 実行
kotlinコマンドもしくはjavaコマンドで作成したjarファイルを実行します。

```
kotlin encrypto.jar 
```

```
java -jar encrypto.jar
```