Skip to content

Commit 527ee5d

Browse files
Merge pull request #812 from kennethshackleton/use-explicit-bzero
Use explicit_bzero for key scrubbing in JNI
2 parents 0727a34 + 22125be commit 527ee5d

3 files changed

Lines changed: 63 additions & 24 deletions

File tree

SQLite3/sqlite3/include/bloomberg/AutoJByteArray.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
#define SELEKT_AUTOJBYTEARRAY_H
1919

2020
#include <jni.h>
21+
#include <cstring>
2122
#include <stdexcept>
2223
#include "Throws.h"
24+
#include "secure_zero.h"
2325

2426
struct JniOutOfMemoryError : std::runtime_error {
2527
using std::runtime_error::runtime_error;
@@ -40,6 +42,7 @@ class AutoJByteArray
4042
}
4143

4244
~AutoJByteArray() {
45+
selekt::secure_zero(reinterpret_cast<unsigned char*>(mpBytes), static_cast<size_t>(mLength));
4346
mEnv->ReleaseByteArrayElements(mJArray, mpBytes, JNI_ABORT);
4447
}
4548

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2020 Bloomberg Finance L.P.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef SELEKT_SECURE_ZERO_H
18+
#define SELEKT_SECURE_ZERO_H
19+
20+
#include <cstddef>
21+
#include <cstring>
22+
23+
#if defined(__GLIBC__) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28)
24+
#include <strings.h>
25+
#endif
26+
27+
namespace selekt {
28+
inline void secure_zero(unsigned char* p, size_t n) {
29+
#if defined(__cpp_lib_memset_explicit) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
30+
memset_explicit(p, 0, n);
31+
#elif defined(__GLIBC__) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28)
32+
explicit_bzero(p, n);
33+
#else
34+
volatile unsigned char* pp = p;
35+
while (n--) { *pp++ = 0; }
36+
#endif
37+
}
38+
}
39+
40+
#endif //SELEKT_SECURE_ZERO_H

SQLite3/sqlite3_jni.cpp

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,8 @@ void throwOutOfMemoryError(JNIEnv* env, const char* message) {
100100
}
101101
}
102102

103-
static inline void updateHolder(JNIEnv* env, jlongArray array, int offset, void* p) {
104-
auto val = reinterpret_cast<jlong>(p);
105-
env->SetLongArrayRegion(array, offset, 1, &val);
103+
static inline void updateHolder(JNIEnv* env, jlongArray array, int offset, jlong value) {
104+
env->SetLongArrayRegion(array, offset, 1, &value);
106105
}
107106

108107
static jbyteArray newByteArray(JNIEnv* env, const void* p, jsize size) {
@@ -133,24 +132,21 @@ static jint rawKey(
133132
return SQLITE_ERROR;
134133
}
135134
try {
136-
AutoJByteArray key(env, jkey, keyLength);
137-
char sql[81];
138-
std::memcpy(sql, "PRAGMA key=\"x'", 14);
139-
const char hex_chars[] = "0123456789abcdef";
140-
for (int i = 0; i < keyLength; ++i) {
141-
auto byte = static_cast<std::byte>(key[i]);
142-
sql[14 + 2*i] = hex_chars[std::to_integer<unsigned char>(byte >> 4)];
143-
sql[14 + 2*i + 1] = hex_chars[std::to_integer<unsigned char>(byte & std::byte{0xF})];
144-
}
145-
sql[78] = '\'';
146-
sql[79] = '"';
147-
sql[80] = '\0';
148-
auto result = sqlite3_exec(reinterpret_cast<sqlite3*>(jdb), sql, nullptr, nullptr, nullptr);
149-
volatile char* p = sql;
150-
for (size_t i = 0; i < sizeof(sql); ++i) {
151-
p[i] = '\0';
152-
}
153-
return result;
135+
AutoJByteArray key(env, jkey, keyLength);
136+
char sql[81];
137+
std::memcpy(sql, "PRAGMA key=\"x'", 14);
138+
const char hex_chars[] = "0123456789abcdef";
139+
for (int i = 0; i < keyLength; ++i) {
140+
auto byte = static_cast<std::byte>(key[i]);
141+
sql[14 + 2*i] = hex_chars[std::to_integer<unsigned char>(byte >> 4)];
142+
sql[15 + 2*i] = hex_chars[std::to_integer<unsigned char>(byte & std::byte{0xF})];
143+
}
144+
sql[78] = '\'';
145+
sql[79] = '"';
146+
sql[80] = '\0';
147+
auto result = sqlite3_exec(reinterpret_cast<sqlite3*>(jdb), sql, nullptr, nullptr, nullptr);
148+
selekt::secure_zero(reinterpret_cast<unsigned char*>(sql), sizeof(sql));
149+
return result;
154150
} catch (const JniOutOfMemoryError&) {
155151
return SQLITE_NOMEM;
156152
}
@@ -356,7 +352,7 @@ Java_com_bloomberg_selekt_ExternalSQLite_blobOpen(
356352
env->ReleaseStringUTFChars(jtable, table);
357353
env->ReleaseStringUTFChars(jcolumn, column);
358354
if (result == SQLITE_OK) {
359-
updateHolder(env, jholder, 0, blob);
355+
updateHolder(env, jholder, 0, reinterpret_cast<jlong>(blob));
360356
}
361357
return result;
362358
}
@@ -970,7 +966,7 @@ Java_com_bloomberg_selekt_ExternalSQLite_openV2(
970966
}
971967
auto result = sqlite3_open_v2(filename, &db, jflags, nullptr);
972968
env->ReleaseStringUTFChars(jfilename, filename);
973-
updateHolder(env, dbHolder, 0, db);
969+
updateHolder(env, dbHolder, 0, reinterpret_cast<jlong>(db));
974970
return result;
975971
}
976972

@@ -992,7 +988,7 @@ Java_com_bloomberg_selekt_ExternalSQLite_prepareV2(
992988
auto result = sqlite3_prepare_v2(reinterpret_cast<sqlite3*>(jdb), sql, jlength, &statement, nullptr);
993989
env->ReleaseStringUTFChars(jsql, sql);
994990
if (result == SQLITE_OK) {
995-
updateHolder(env, statementHolder, 0, statement);
991+
updateHolder(env, statementHolder, 0, reinterpret_cast<jlong>(statement));
996992
}
997993
return result;
998994
}

0 commit comments

Comments
 (0)