Skip to content

Commit

Permalink
Merge pull request #98 from kennethshackleton/jni-raw-key
Browse files Browse the repository at this point in the history
Move key stringing off the Java heap and into jni.
  • Loading branch information
kennethshackleton authored May 8, 2021
2 parents 1f7c33b + 2ccad0e commit 1ad2309
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 4 deletions.
15 changes: 12 additions & 3 deletions Lib/src/main/kotlin/com/bloomberg/selekt/Key.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

package com.bloomberg.selekt

import com.bloomberg.selekt.annotations.Generated
import com.bloomberg.selekt.commons.zero

private const val KEY_SIZE = 32
private fun ByteArray.asBlobLiteral() = "x'${joinToString("") { "%02X".format(it) }}'"

internal class Key(value: ByteArray) {
init {
Expand All @@ -31,7 +33,14 @@ internal class Key(value: ByteArray) {
value.fill(0)
}

operator fun invoke() = synchronized(lock) {
value.asBlobLiteral()
@Generated
inline fun <R> use(action: (ByteArray) -> R) = synchronized(lock) {
value.copyOf()
}.let {
try {
action(it)
} finally {
it.zero()
}
}
}
2 changes: 1 addition & 1 deletion Lib/src/main/kotlin/com/bloomberg/selekt/SQLConnection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ internal class SQLConnection constructor(

init {
runCatching {
key?.let { sqlite.exec(pointer, "PRAGMA key=\"${it()}\"") }
key?.use { sqlite.rawKey(pointer, it) }
sqlite.extendedResultCodes(pointer, 0)
configuration.trace?.let { sqlite.traceV2(pointer, it()) }
sqlite.busyTimeout(pointer, configuration.busyTimeoutMillis)
Expand Down
2 changes: 2 additions & 0 deletions Lib/src/main/kotlin/com/bloomberg/selekt/SQLite.kt
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ open class SQLite(
statementHolder: LongArray
) = checkConnectionSQLCode(db, sqlite.prepareV2(db, sql, sql.length, statementHolder))

fun rawKey(db: Long, key: ByteArray) = checkConnectionSQLCode(db, sqlite.rawKey(db, key, key.size))

fun rekey(db: Long, key: ByteArray) = checkConnectionSQLCode(db, sqlite.rekey(db, key, key.size))

fun releaseMemory(bytes: Int) = sqlite.releaseMemory(bytes)
Expand Down
19 changes: 19 additions & 0 deletions Lib/src/main/kotlin/com/bloomberg/selekt/commons/ByteArrays.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2021 Bloomberg Finance L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.bloomberg.selekt.commons

internal fun ByteArray.zero() = fill(0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2021 Bloomberg Finance L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.bloomberg.selekt.commons

import org.junit.jupiter.api.Test
import kotlin.test.assertEquals

internal class ByteArraysKtTest {
@Test
fun zero() {
byteArrayOf(0x42).let {
it.zero()
assertEquals(0, it.first())
}
}
}
26 changes: 26 additions & 0 deletions SQLite3/sqlite3_jni.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,32 @@ Java_com_bloomberg_selekt_ExternalSQLite_prepareV2(
return result;
}

extern "C" JNIEXPORT jint JNICALL
Java_com_bloomberg_selekt_ExternalSQLite_rawKey(
JNIEnv* env,
jobject jobj,
jlong jdb,
jbyteArray jkey,
jint keyLength
) {
AutoJByteArray key(env, jkey, keyLength);
std::string prefix = "PRAGMA key=\"x'";
std::string suffix = "'\"";
size_t const length = prefix.length() + (2 * keyLength) + suffix.length();
char sql[length + 1];
sql[length] = 0;
std::strcpy(sql, prefix.c_str());
int i;
char * const hex = sql + prefix.length();
for (i = 0; i < keyLength; ++i) {
std::sprintf(hex + (2 * i), "%02x", key[i]);
}
std::strcpy(sql + length - suffix.length(), suffix.c_str());
auto result = sqlite3_exec(reinterpret_cast<sqlite3*>(jdb), sql, nullptr, nullptr, nullptr);
std::fill(sql, sql + length + 1, 0);
return result;
}

extern "C" JNIEXPORT jint JNICALL
Java_com_bloomberg_selekt_ExternalSQLite_rekey(
JNIEnv* env,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ class ExternalSQLite private constructor(

external fun prepareV2(db: Long, sql: String, length: Int, statementHolder: LongArray): SQLCode

external fun rawKey(db: Long, key: ByteArray, length: Int): SQLCode

external fun rekey(db: Long, key: ByteArray, length: Int): SQLCode

external fun releaseMemory(bytes: Int): Int
Expand Down

0 comments on commit 1ad2309

Please sign in to comment.