Android の gradle プロジェクトで、ビルド時ファイルの暗号化を

Android アプリをビルドする gradle プロジェクトで、ビルドの際に、ファイルの暗号化をしたい。

コマンドラインツールで手当てしても良かったのですが…

- 開発環境が Windows マシン
- CI 環境の OS が Linux

という点を考えると、OS に依存しない方法で実現したい気持ちになります。

幸いにも昨今の Java はクラスライブラリが充実しており、
Java で完結できるという感触がありました。

何らかの Java コードを書くわけですが、
gradle plugin とか勉強してプラグインを一本、書かなければいけないのかなーと思っていました。

`app/build.gradle` の中で、普通に Groovy (Java) のプログラムを書くことが出来ると分かって狂喜しました。これは単なる設定ファイルではないのだ、と。

```gradle
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec

def encryptFile(String inputFile, String outputFile, String ivString, String keyString) {
    def inputBinary = new File(inputFile).readBytes()
    def encrypt = Cipher.getInstance("AES/CBC/PKCS5Padding")
    def iv = new IvParameterSpec(ivString.getBytes())
    def key = new SecretKeySpec(keyString.getBytes(), "AES")
    encrypt.init(Cipher.ENCRYPT_MODE, key, iv)
    def outputBinary = encrypt.doFinal(inputBinary)
    new File(outputFile).setBytes(outputBinary)
}

task eatThis {
    doFirst {
        encryptFile(
                "$projectDir/test.txt",
                "$projectDir/src/main/res/raw/test",
                "1234567812345678",
                "1234567812345678"
        )
    }
}
```

※ Java のコードは [【Java】標準ライブラリでAES暗号で暗号化する方法](https://qiita.com/tamorieeeen/items/57585d585a06f6d2d015) を参考にさせて頂きました!

`def encryptFile(String inputFile, String outputFile, String ivString, String keyString)` というメソッドのようなものを動的に定義しています。

`encryptFile` を宣言し、それを後で使用するという手法は、手続き型プログラミングではよくある事として…

Groovy Language Documentation の [3.15.1. Command chains](http://docs.groovy-lang.org/docs/groovy-2.5.0-beta-1/html/documentation/#_command_chains) を見ると、狂気を感じます ↓

```groovy
// equivalent to: turn(left).then(right)
turn left then right

// equivalent to: take(2.pills).of(chloroquinine).after(6.hours)
take 2.pills of chloroquinine after 6.hours

// equivalent to: paint(wall).with(red, green).and(yellow)
paint wall with red, green and yellow

// with named parameters too
// equivalent to: check(that: margarita).tastes(good)
check that: margarita tastes good

// with closures as parameters
// equivalent to: given({}).when({}).then({})
given { } when { } then { }
```

`func(param)` の用法が当たり前だと思っていた自分には、この Command chains は中々衝撃的でした。

その Command chains の学びを実践して `encryptFrom` を作ってみました。

```gradle
def encryptFrom(inputFile) {
    [to: { outputFile ->
        [iv: { ivString ->
            [key: { keyString ->
                def inputBinary = new File(inputFile).readBytes()
                def encrypt = Cipher.getInstance("AES/CBC/PKCS5Padding")
                def key = new SecretKeySpec(keyString.getBytes(), "AES")
                def iv = new IvParameterSpec(ivString.getBytes())
                encrypt.init(Cipher.ENCRYPT_MODE, key, iv)
                def outputBinary = encrypt.doFinal(inputBinary)
                new File(outputFile).setBytes(outputBinary)
            }]
        }]
    }]
}

task eatThis {
    doFirst {
        encryptFrom "$projectDir/test.txt" to "$projectDir/src/main/res/raw/test" iv "1234567812345678" key "1234567812345678"
    }
}
```

Command chains については初学者でありますので、パラメータの順番は固定になっていますが…
後から見ても (パラメータの引数が明瞭で) メンテしやすいものができた、と思います。