Skip to content

Commit

Permalink
EXPOSED-203 Lightweight DAO insert with encryptedVarchar attemtps to … (
Browse files Browse the repository at this point in the history
#2194)

* EXPOSED-203 Lightweight DAO insert with encryptedVarchar attemtps to decrypt unencrypted input
  • Loading branch information
obabichevjb authored Aug 12, 2024
1 parent 7c3df2f commit e63f35b
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 89 deletions.
2 changes: 1 addition & 1 deletion exposed-core/api/exposed-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ public final class org/jetbrains/exposed/sql/ColumnTypeKt {
public static synthetic fun resolveColumnType$default (Lkotlin/reflect/KClass;Lorg/jetbrains/exposed/sql/ColumnType;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/ColumnType;
}

public final class org/jetbrains/exposed/sql/ColumnWithTransform : org/jetbrains/exposed/sql/ColumnType, org/jetbrains/exposed/sql/ColumnTransformer {
public class org/jetbrains/exposed/sql/ColumnWithTransform : org/jetbrains/exposed/sql/ColumnType, org/jetbrains/exposed/sql/ColumnTransformer {
public fun <init> (Lorg/jetbrains/exposed/sql/IColumnType;Lorg/jetbrains/exposed/sql/ColumnTransformer;)V
public final fun getDelegate ()Lorg/jetbrains/exposed/sql/IColumnType;
public fun getNullable ()Z
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ fun <Unwrapped, Wrapped>columnTransformer(unwrap: (value: Wrapped) -> Unwrapped,
* @param Unwrapped The type of the column
* @param delegate The original column's [IColumnType]
*/
class ColumnWithTransform<Unwrapped : Any, Wrapped : Any>(
open class ColumnWithTransform<Unwrapped : Any, Wrapped : Any>(
val delegate: IColumnType<Unwrapped>,
private val transformer: ColumnTransformer<Unwrapped, Wrapped>
) : ColumnType<Wrapped>(), ColumnTransformer<Unwrapped, Wrapped> by transformer {
Expand Down
40 changes: 18 additions & 22 deletions exposed-crypt/api/exposed-crypt.api
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,20 @@ public final class org/jetbrains/exposed/crypt/Algorithms {
public final fun TRIPLE_DES (Ljava/lang/CharSequence;)Lorg/jetbrains/exposed/crypt/Encryptor;
}

public final class org/jetbrains/exposed/crypt/EncryptedBinaryColumnType : org/jetbrains/exposed/sql/BinaryColumnType {
public final class org/jetbrains/exposed/crypt/ByteArrayEncryptionTransformer : org/jetbrains/exposed/sql/ColumnTransformer {
public fun <init> (Lorg/jetbrains/exposed/crypt/Encryptor;)V
public synthetic fun unwrap (Ljava/lang/Object;)Ljava/lang/Object;
public fun unwrap ([B)[B
public synthetic fun wrap (Ljava/lang/Object;)Ljava/lang/Object;
public fun wrap ([B)[B
}

public final class org/jetbrains/exposed/crypt/EncryptedBinaryColumnType : org/jetbrains/exposed/sql/ColumnWithTransform {
public fun <init> (Lorg/jetbrains/exposed/crypt/Encryptor;I)V
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public synthetic fun nonNullValueToString (Ljava/lang/Object;)Ljava/lang/String;
public fun nonNullValueToString ([B)Ljava/lang/String;
public synthetic fun notNullValueToDB (Ljava/lang/Object;)Ljava/lang/Object;
public fun notNullValueToDB ([B)[B
public synthetic fun validateValueBeforeUpdate (Ljava/lang/Object;)V
public fun validateValueBeforeUpdate ([B)V
public synthetic fun valueFromDB (Ljava/lang/Object;)Ljava/lang/Object;
public fun valueFromDB (Ljava/lang/Object;)[B
}

public final class org/jetbrains/exposed/crypt/EncryptedVarCharColumnType : org/jetbrains/exposed/sql/VarCharColumnType {
public final class org/jetbrains/exposed/crypt/EncryptedVarCharColumnType : org/jetbrains/exposed/sql/ColumnWithTransform {
public fun <init> (Lorg/jetbrains/exposed/crypt/Encryptor;I)V
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public synthetic fun nonNullValueToString (Ljava/lang/Object;)Ljava/lang/String;
public fun nonNullValueToString (Ljava/lang/String;)Ljava/lang/String;
public synthetic fun notNullValueToDB (Ljava/lang/Object;)Ljava/lang/Object;
public fun notNullValueToDB (Ljava/lang/String;)Ljava/lang/String;
public synthetic fun validateValueBeforeUpdate (Ljava/lang/Object;)V
public fun validateValueBeforeUpdate (Ljava/lang/String;)V
public synthetic fun valueFromDB (Ljava/lang/Object;)Ljava/lang/Object;
public fun valueFromDB (Ljava/lang/Object;)Ljava/lang/String;
}

public final class org/jetbrains/exposed/crypt/Encryptor {
Expand All @@ -44,6 +32,14 @@ public final class org/jetbrains/exposed/crypt/Encryptor {
public final fun maxColLength (I)I
}

public final class org/jetbrains/exposed/crypt/StringEncryptionTransformer : org/jetbrains/exposed/sql/ColumnTransformer {
public fun <init> (Lorg/jetbrains/exposed/crypt/Encryptor;)V
public synthetic fun unwrap (Ljava/lang/Object;)Ljava/lang/Object;
public fun unwrap (Ljava/lang/String;)Ljava/lang/String;
public synthetic fun wrap (Ljava/lang/Object;)Ljava/lang/Object;
public fun wrap (Ljava/lang/String;)Ljava/lang/String;
}

public final class org/jetbrains/exposed/crypt/TablesKt {
public static final fun encryptedBinary (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;ILorg/jetbrains/exposed/crypt/Encryptor;)Lorg/jetbrains/exposed/sql/Column;
public static final fun encryptedVarchar (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;ILorg/jetbrains/exposed/crypt/Encryptor;)Lorg/jetbrains/exposed/sql/Column;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.jetbrains.exposed.crypt

import org.jetbrains.exposed.sql.BinaryColumnType
import org.jetbrains.exposed.sql.ColumnTransformer
import org.jetbrains.exposed.sql.ColumnWithTransform

/**
* Binary column for storing encrypted binary strings of a specific [length], using the provided [encryptor].
Expand All @@ -10,37 +12,10 @@ import org.jetbrains.exposed.sql.BinaryColumnType
class EncryptedBinaryColumnType(
private val encryptor: Encryptor,
length: Int
) : BinaryColumnType(length) {
override fun nonNullValueToString(value: ByteArray): String {
return super.nonNullValueToString(notNullValueToDB(value))
}
) : ColumnWithTransform<ByteArray, ByteArray>(BinaryColumnType(length), ByteArrayEncryptionTransformer(encryptor))

override fun notNullValueToDB(value: ByteArray): ByteArray = encryptor.encrypt(String(value)).toByteArray()
class ByteArrayEncryptionTransformer(private val encryptor: Encryptor) : ColumnTransformer<ByteArray, ByteArray> {
override fun unwrap(value: ByteArray) = encryptor.encrypt(String(value)).toByteArray()

override fun valueFromDB(value: Any): ByteArray {
val encryptedByte = super.valueFromDB(value)
return encryptor.decrypt(String(encryptedByte)).toByteArray()
}

override fun validateValueBeforeUpdate(value: ByteArray?) {
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

return encryptor == other.encryptor
}

override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + encryptor.hashCode()
return result
}
override fun wrap(value: ByteArray) = encryptor.decrypt(String(value)).toByteArray()
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jetbrains.exposed.crypt

import org.jetbrains.exposed.sql.ColumnTransformer
import org.jetbrains.exposed.sql.ColumnWithTransform
import org.jetbrains.exposed.sql.VarCharColumnType

/**
Expand All @@ -10,40 +12,11 @@ import org.jetbrains.exposed.sql.VarCharColumnType
*/
class EncryptedVarCharColumnType(
private val encryptor: Encryptor,
colLength: Int,
) : VarCharColumnType(colLength) {
override fun nonNullValueToString(value: String): String {
return super.nonNullValueToString(notNullValueToDB(value))
}
colLength: Int
) : ColumnWithTransform<String, String>(VarCharColumnType(colLength), StringEncryptionTransformer(encryptor))

override fun notNullValueToDB(value: String): String {
return encryptor.encrypt(value)
}
class StringEncryptionTransformer(private val encryptor: Encryptor) : ColumnTransformer<String, String> {
override fun unwrap(value: String) = encryptor.encrypt(value)

override fun valueFromDB(value: Any): String {
val encryptedStr = super.valueFromDB(value)
return encryptor.decrypt(encryptedStr)
}

override fun validateValueBeforeUpdate(value: String?) {
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

return encryptor == other.encryptor
}

override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + encryptor.hashCode()
return result
}
override fun wrap(value: String) = encryptor.decrypt(value)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.jetbrains.exposed.crypt

import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.tests.shared.assertEquals
import org.junit.Test

class EncryptedColumnDaoTests : DatabaseTestsBase() {
object TestTable : IntIdTable() {
val varchar = encryptedVarchar("varchar", 100, Algorithms.AES_256_PBE_GCM("passwd", "12345678"))
val binary = encryptedBinary("binary", 100, Algorithms.AES_256_PBE_GCM("passwd", "12345678"))
}

class ETest(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<ETest>(TestTable)

var varchar by TestTable.varchar
var binary by TestTable.binary
}

@Test
fun testEncryptedColumnsWithDao() {
withTables(TestTable) {
val varcharValue = "varchar"
val binaryValue = "binary".toByteArray()

val entity = ETest.new {
varchar = varcharValue
binary = binaryValue
}
assertEquals(varcharValue, entity.varchar)
assertEquals(binaryValue, entity.binary)

TestTable.selectAll().first().let {
assertEquals(varcharValue, it[TestTable.varchar])
assertEquals(String(binaryValue), String(it[TestTable.binary]))
}
}
}
}

0 comments on commit e63f35b

Please sign in to comment.