Mercurial > cgi-bin > hgweb.cgi > PassMan
annotate src/main/kotlin/name/blackcap/passman/Encryption.kt @ 20:4391afcf6bd0
Fix more bugs, correct more bad tests.
author | David Barts <n5jrn@me.com> |
---|---|
date | Sun, 30 Jun 2024 22:28:52 -0700 |
parents | 698c4a3d758d |
children |
rev | line source |
---|---|
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
1 package name.blackcap.passman |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
2 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
3 import java.nio.ByteBuffer |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
4 import java.nio.CharBuffer |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
5 import java.nio.charset.Charset |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
6 import java.nio.charset.StandardCharsets |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
7 import java.security.SecureRandom |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
8 import javax.crypto.Cipher |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
9 import javax.crypto.SecretKey |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
10 import javax.crypto.SecretKeyFactory |
6
711cc42e96d7
Got the list subcommand working, but needs efficiency improvements.
David Barts <n5jrn@me.com>
parents:
0
diff
changeset
|
11 |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
12 import javax.crypto.spec.IvParameterSpec |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
13 import javax.crypto.spec.PBEKeySpec |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
14 import javax.crypto.spec.SecretKeySpec |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
15 import javax.security.auth.Destroyable |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
16 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
17 class Encryption(passwordIn: CharArray, saltIn: ByteArray) : Destroyable { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
18 private companion object { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
19 const val ITERATIONS = 390000 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
20 const val IV_LENGTH = 16 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
21 const val KEY_LENGTH = 256 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
22 const val ENCRYPTION_ALGORITHM = "AES/CBC/PKCS5Padding" |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
23 const val KEY_ALGORITHM = "AES" |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
24 const val SECRET_KEY_FACTORY = "PBKDF2WithHmacSHA256" |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
25 val CHARSET : Charset = StandardCharsets.UTF_8 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
26 val ZERO_IV = ByteArray(IV_LENGTH).apply { clear() } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
27 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
28 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
29 private val secretKey = getSecretKey(passwordIn, saltIn) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
30 private val secureRandom = SecureRandom() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
31 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
32 fun encrypt(plaintext: CharArray): ByteArray { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
33 val iv = ByteArray(IV_LENGTH).also { secureRandom.nextBytes(it) } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
34 return encrypt(plaintext, iv) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
35 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
36 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
37 private fun encrypt(plaintext: CharArray, iv: ByteArray): ByteArray { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
38 val cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
39 cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivFactory(iv)) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
40 val inBuffer = CHARSET.encode(CharBuffer.wrap(plaintext)) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
41 val outBuffer = ByteBuffer.allocate(cipher.getOutputSize(inBuffer.limit()) + IV_LENGTH) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
42 outBuffer.put(iv) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
43 cipher.doFinal(inBuffer, outBuffer) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
44 return outBuffer.array() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
45 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
46 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
47 fun encryptFromString(plaintext: String): ByteArray = encrypt(plaintext.toCharArray()) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
48 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
49 fun encryptFromString0(plaintext: String): ByteArray = |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
50 encrypt(plaintext.toCharArray(), ZERO_IV) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
51 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
52 fun decrypt(ciphertext: ByteArray): CharArray { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
53 val cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
54 cipher.init(Cipher.DECRYPT_MODE, secretKey, ivFactory(ciphertext)) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
55 val bytes = cipher.doFinal(ciphertext, IV_LENGTH, ciphertext.size - IV_LENGTH) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
56 val charBuffer = CHARSET.decode(ByteBuffer.wrap(bytes)) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
57 bytes.clear() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
58 val ret = CharArray(charBuffer.limit()) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
59 charBuffer.run { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
60 rewind() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
61 get(ret) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
62 zero() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
63 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
64 return ret |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
65 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
66 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
67 fun decryptToString(ciphertext: ByteArray): String = String(decrypt(ciphertext)) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
68 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
69 override fun destroy() { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
70 secretKey.destroy() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
71 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
72 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
73 override fun isDestroyed(): Boolean { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
74 return secretKey.isDestroyed |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
75 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
76 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
77 protected fun finalize() { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
78 destroy() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
79 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
80 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
81 private fun getSecretKey(password: CharArray, salt: ByteArray): SecretKey { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
82 val factory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
83 val spec = PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
84 return SecretKeySpec(factory.generateSecret(spec).encoded, KEY_ALGORITHM) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
85 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
86 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
87 private fun ivFactory(ciphertext: ByteArray) = IvParameterSpec(ciphertext, 0, IV_LENGTH) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
88 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
89 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
90 fun ByteArray.clear() = indices.forEach { this[it] = 0 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
91 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
92 fun CharArray.clear() = indices.forEach { this[it] = '\u0000' } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
93 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
94 fun CharBuffer.zero() { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
95 clear() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
96 array().clear() |
8 | 97 } |