aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/org/pacien/tincapp/utils/PemUtils.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org/pacien/tincapp/utils/PemUtils.kt')
-rw-r--r--app/src/main/java/org/pacien/tincapp/utils/PemUtils.kt62
1 files changed, 62 insertions, 0 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/utils/PemUtils.kt b/app/src/main/java/org/pacien/tincapp/utils/PemUtils.kt
new file mode 100644
index 0000000..3d59476
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/utils/PemUtils.kt
@@ -0,0 +1,62 @@
1package org.pacien.tincapp.utils
2
3import org.bouncycastle.openssl.PEMException
4import org.bouncycastle.openssl.PEMParser
5import org.bouncycastle.openssl.jcajce.JcaPEMWriter
6import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder
7import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder
8import org.bouncycastle.util.encoders.Hex
9import org.bouncycastle.util.io.pem.PemHeader
10import org.bouncycastle.util.io.pem.PemObject
11import java.io.File
12import java.io.FileReader
13import java.io.Writer
14
15/**
16 * @author pacien
17 */
18object PemUtils {
19
20 private val PROVIDER = org.bouncycastle.jce.provider.BouncyCastleProvider()
21 private val ENCRYPTED_PROC_TYPE_HEADER = PemHeader("Proc-Type", "4,ENCRYPTED")
22 private val DEK_INFO_HEADER_KEY = "DEK-Info"
23 private val ALGO = "AES-256-CBC"
24
25 private class DekInfo(val algName: String, val iv: ByteArray)
26
27 private fun dekInfoHeader(iv: ByteArray) = PemHeader(DEK_INFO_HEADER_KEY, "$ALGO,${Hex.toHexString(iv)}")
28 private fun PemObject.getPemHeaders() = headers.map { it as PemHeader }
29
30 fun read(f: File): PemObject = PEMParser(FileReader(f)).readPemObject()
31 fun write(obj: PemObject, out: Writer) = JcaPEMWriter(out).apply { writeObject(obj) }.apply { close() }
32 fun isEncrypted(obj: PemObject) = obj.headers.contains(ENCRYPTED_PROC_TYPE_HEADER)
33
34 fun encrypt(obj: PemObject, passPhrase: String) =
35 JcePEMEncryptorBuilder(ALGO)
36 .setProvider(PROVIDER)
37 .build(passPhrase.toCharArray())
38 .let { PemObject(obj.type, listOf(ENCRYPTED_PROC_TYPE_HEADER, dekInfoHeader(it.iv)), it.encrypt(obj.content)) }
39
40 fun decrypt(obj: PemObject, passPhrase: String?) =
41 if (isEncrypted(obj)) {
42 val dekInfo = try {
43 obj.getPemHeaders()
44 .find { it.name == DEK_INFO_HEADER_KEY }!!
45 .value!!
46 .split(',')
47 .let { DekInfo(it[0], Hex.decode(it[1])) }
48 } catch (e: Exception) {
49 throw PEMException("Malformed DEK-Info header.", e)
50 }
51
52 JcePEMDecryptorProviderBuilder()
53 .setProvider(PROVIDER)
54 .build(passPhrase?.toCharArray())
55 .get(dekInfo.algName)
56 .decrypt(obj.content, dekInfo.iv)
57 .let { PemObject(obj.type, it) }
58 } else {
59 obj
60 }
61
62}