forked from JetBrains/Exposed
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aec4ee5
commit e71370e
Showing
12 changed files
with
323 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
plugins { | ||
kotlin("jvm") apply true | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
api(project(":exposed-core")) | ||
api("org.springframework.security", "spring-security-crypto", "5.5.3") | ||
} |
106 changes: 106 additions & 0 deletions
106
exposed-crypt/src/main/kotlin/org/jetbrains/exposed/crypt/Algorithms.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package org.jetbrains.exposed.crypt | ||
|
||
import org.springframework.security.crypto.encrypt.AesBytesEncryptor | ||
import org.springframework.security.crypto.keygen.KeyGenerators | ||
import org.springframework.security.crypto.util.EncodingUtils | ||
import java.util.* | ||
import javax.crypto.Cipher | ||
import javax.crypto.spec.IvParameterSpec | ||
import javax.crypto.spec.SecretKeySpec | ||
import kotlin.math.ceil | ||
|
||
object Algorithms { | ||
private fun base64EncodedLength(byteSize: Int): Int = ceil(byteSize.toDouble() / 3).toInt() * 4 | ||
private fun paddingLen(len: Int, blockSize: Int): Int = if (len % blockSize == 0) 0 else blockSize - len % blockSize | ||
private val base64Decoder = Base64.getDecoder() | ||
private val base64Encoder = Base64.getEncoder() | ||
|
||
private const val AES_256_GCM_BLOCK_LENGTH = 16 | ||
private const val AES_256_GCM_TAG_LENGTH = 16 | ||
@Suppress("FunctionNaming") | ||
fun AES_256_PBE_GCM(password: CharSequence, salt: CharSequence): Encryptor { | ||
|
||
return AesBytesEncryptor(password.toString(), | ||
salt, | ||
KeyGenerators.secureRandom(AES_256_GCM_BLOCK_LENGTH), | ||
AesBytesEncryptor.CipherAlgorithm.GCM) | ||
.run { | ||
Encryptor({ base64Encoder.encodeToString(encrypt(it.toByteArray())) }, | ||
{ String(decrypt(base64Decoder.decode(it))) }, | ||
{ inputLen -> | ||
base64EncodedLength(AES_256_GCM_BLOCK_LENGTH + inputLen + AES_256_GCM_TAG_LENGTH) }) | ||
} | ||
} | ||
|
||
private const val AES_256_CBC_BLOCK_LENGTH = 16 | ||
@Suppress("FunctionNaming") | ||
fun AES_256_PBE_CBC(password: CharSequence, salt: CharSequence): Encryptor { | ||
|
||
return AesBytesEncryptor(password.toString(), | ||
salt, | ||
KeyGenerators.secureRandom(AES_256_CBC_BLOCK_LENGTH)) | ||
.run { | ||
Encryptor({ base64Encoder.encodeToString(encrypt(it.toByteArray())) }, | ||
{ String(decrypt(base64Decoder.decode(it))) }, | ||
{ inputLen -> | ||
val paddingSize = (AES_256_CBC_BLOCK_LENGTH - inputLen % AES_256_CBC_BLOCK_LENGTH) | ||
base64EncodedLength(AES_256_CBC_BLOCK_LENGTH + inputLen + paddingSize) }) | ||
} | ||
} | ||
|
||
private const val BLOW_FISH_BLOCK_LENGTH = 8 | ||
@Suppress("FunctionNaming") | ||
fun BLOW_FISH(key: CharSequence): Encryptor { | ||
val ks = SecretKeySpec(key.toString().toByteArray(), "Blowfish") | ||
|
||
return Encryptor( | ||
{ plainText -> | ||
val cipher = Cipher.getInstance("Blowfish") | ||
cipher.init(Cipher.ENCRYPT_MODE, ks) | ||
|
||
val encryptedBytes = cipher.doFinal(plainText.toByteArray()) | ||
base64Encoder.encodeToString(encryptedBytes) | ||
}, | ||
{ encryptedText -> | ||
val cipher = Cipher.getInstance("Blowfish") | ||
cipher.init(Cipher.DECRYPT_MODE, ks) | ||
|
||
val decryptedBytes = cipher.doFinal(base64Decoder.decode(encryptedText)) | ||
String(decryptedBytes) | ||
}, | ||
{ base64EncodedLength(it + paddingLen(it, BLOW_FISH_BLOCK_LENGTH)) }) | ||
} | ||
|
||
private const val TRIPLE_DES_KEY_LENGTH = 24 | ||
private const val TRIPLE_DES_BLOCK_LENGTH = 8 | ||
@Suppress("FunctionNaming") | ||
fun TRIPLE_DES(secretKey: CharSequence): Encryptor { | ||
if (secretKey.toString().toByteArray().size != TRIPLE_DES_KEY_LENGTH) { | ||
throw IllegalArgumentException("secretKey must have 24 bytes") | ||
} | ||
val ks = SecretKeySpec(secretKey.toString().toByteArray(), "TripleDES") | ||
|
||
val ivGenerator = KeyGenerators.secureRandom(TRIPLE_DES_BLOCK_LENGTH) | ||
|
||
return Encryptor( | ||
{ plainText -> | ||
val cipher = Cipher.getInstance("TripleDES/CBC/PKCS5Padding") | ||
val iv = ivGenerator.generateKey() | ||
cipher.init(Cipher.ENCRYPT_MODE, ks, IvParameterSpec(iv)) | ||
|
||
val encryptedBytes = cipher.doFinal(plainText.toByteArray()) | ||
base64Encoder.encodeToString(EncodingUtils.concatenate(iv, encryptedBytes)) | ||
}, | ||
{ encryptedText -> | ||
val cipher = Cipher.getInstance("TripleDES/CBC/PKCS5Padding") | ||
val decodedBytes = base64Decoder.decode(encryptedText.toByteArray()) | ||
|
||
val iv = EncodingUtils.subArray(decodedBytes, 0, TRIPLE_DES_BLOCK_LENGTH) | ||
cipher.init(Cipher.DECRYPT_MODE, ks, IvParameterSpec(iv)) | ||
|
||
val decryptedBytes = cipher.doFinal(EncodingUtils.subArray(decodedBytes, TRIPLE_DES_BLOCK_LENGTH, decodedBytes.size)) | ||
String(decryptedBytes) | ||
}, | ||
{ base64EncodedLength(TRIPLE_DES_BLOCK_LENGTH + it + paddingLen(it, TRIPLE_DES_BLOCK_LENGTH)) }) | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
exposed-crypt/src/main/kotlin/org/jetbrains/exposed/crypt/EncryptedBinaryColumnType.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package org.jetbrains.exposed.crypt | ||
|
||
import org.jetbrains.exposed.sql.BinaryColumnType | ||
|
||
class EncryptedBinaryColumnType( | ||
private val encryptor: Encryptor, | ||
length: Int | ||
) : BinaryColumnType(length) { | ||
override fun notNullValueToDB(value: Any): Any { | ||
if (value !is ByteArray) { | ||
error("Unexpected value of type Byte: $value of ${value::class.qualifiedName}") | ||
} | ||
|
||
return encryptor.encrypt(String(value)).toByteArray() | ||
} | ||
|
||
override fun valueFromDB(value: Any): Any { | ||
val encryptedByte = super.valueFromDB(value) | ||
|
||
if (encryptedByte !is ByteArray) { | ||
error("Unexpected value of type Byte: $value of ${value::class.qualifiedName}") | ||
} | ||
|
||
return encryptor.decrypt(String(encryptedByte)).toByteArray() | ||
} | ||
|
||
override fun validateValueBeforeUpdate(value: Any?) { | ||
if (value != null) { | ||
super.validateValueBeforeUpdate(notNullValueToDB(value)) | ||
} | ||
} | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (javaClass != other?.javaClass) return false | ||
if (!super.equals(other)) return false | ||
|
||
other as EncryptedBinaryColumnType | ||
|
||
if (encryptor != other.encryptor) return false | ||
|
||
return true | ||
} | ||
|
||
override fun hashCode(): Int { | ||
var result = super.hashCode() | ||
result = 31 * result + encryptor.hashCode() | ||
return result | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
exposed-crypt/src/main/kotlin/org/jetbrains/exposed/crypt/EncryptedVarCharColumnType.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.jetbrains.exposed.crypt | ||
|
||
import org.jetbrains.exposed.sql.VarCharColumnType | ||
|
||
class EncryptedVarCharColumnType( | ||
private val encryptor: Encryptor, | ||
colLength: Int, | ||
) : VarCharColumnType(colLength) { | ||
override fun notNullValueToDB(value: Any): Any { | ||
return encryptor.encrypt(value.toString()) | ||
} | ||
|
||
override fun valueFromDB(value: Any): Any { | ||
val encryptedStr = super.valueFromDB(value) | ||
|
||
if (encryptedStr !is String) { | ||
error("Unexpected value of type String: $value of ${value::class.qualifiedName}") | ||
} | ||
|
||
return encryptor.decrypt(encryptedStr) | ||
} | ||
|
||
override fun validateValueBeforeUpdate(value: Any?) { | ||
if (value != null) { | ||
super.validateValueBeforeUpdate(notNullValueToDB(value)) | ||
} | ||
} | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (javaClass != other?.javaClass) return false | ||
if (!super.equals(other)) return false | ||
|
||
other as EncryptedVarCharColumnType | ||
|
||
if (encryptor != other.encryptor) return false | ||
|
||
return true | ||
} | ||
|
||
override fun hashCode(): Int { | ||
var result = super.hashCode() | ||
result = 31 * result + encryptor.hashCode() | ||
return result | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
exposed-crypt/src/main/kotlin/org/jetbrains/exposed/crypt/Encryptor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.jetbrains.exposed.crypt | ||
|
||
class Encryptor( | ||
val encryptFn: (String) -> String, | ||
val decryptFn: (String) -> String, | ||
val maxColLengthFn: (Int) -> Int | ||
) { | ||
fun encrypt(str: String) = encryptFn(str) | ||
fun decrypt(str: String) = decryptFn(str) | ||
fun maxColLength(inputByteSize: Int) = maxColLengthFn(inputByteSize) | ||
} |
10 changes: 10 additions & 0 deletions
10
exposed-crypt/src/main/kotlin/org/jetbrains/exposed/crypt/Tables.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package org.jetbrains.exposed.crypt | ||
|
||
import org.jetbrains.exposed.sql.Column | ||
import org.jetbrains.exposed.sql.Table | ||
|
||
fun Table.encryptedVarchar(name: String, cipherTextLength: Int, encryptor: Encryptor): Column<String> = | ||
registerColumn(name, EncryptedVarCharColumnType(encryptor, cipherTextLength)) | ||
|
||
fun Table.encryptedBinary(name: String, cipherByteLength: Int, encryptor: Encryptor): Column<ByteArray> = | ||
registerColumn(name, EncryptedBinaryColumnType(encryptor, cipherByteLength)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters