sqlce 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sqlce-0.1.0 → sqlce-0.1.1}/PKG-INFO +6 -5
- {sqlce-0.1.0 → sqlce-0.1.1}/README.md +5 -4
- {sqlce-0.1.0 → sqlce-0.1.1}/bindings/src/module.cpp +39 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/CMakeLists.txt +5 -1
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/application/SdfDatabase.hpp +6 -0
- sqlce-0.1.1/core/include/sdf/domain/EncryptionMode.hpp +48 -0
- sqlce-0.1.1/core/include/sdf/domain/IPageCipher.hpp +23 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/PageLayout.hpp +8 -0
- sqlce-0.1.1/core/include/sdf/infrastructure/AesCbc.hpp +30 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/infrastructure/FileStorage.hpp +7 -0
- sqlce-0.1.1/core/include/sdf/infrastructure/Sha256.hpp +16 -0
- sqlce-0.1.1/core/include/sdf/infrastructure/Sha512.hpp +16 -0
- sqlce-0.1.1/core/include/sdf/parsing/SdfPageCipher.hpp +41 -0
- {sqlce-0.1.0/core/app → sqlce-0.1.1/core}/main.cpp +67 -27
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/application/SdfDatabase.cpp +23 -2
- sqlce-0.1.1/core/src/infrastructure/AesCbc.cpp +230 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/infrastructure/FileStorage.cpp +43 -0
- sqlce-0.1.1/core/src/infrastructure/Sha256.cpp +126 -0
- sqlce-0.1.1/core/src/infrastructure/Sha512.cpp +144 -0
- sqlce-0.1.1/core/src/parsing/SdfPageCipher.cpp +151 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/docs/build.txt +5 -2
- sqlce-0.1.1/docs/en/cpp.md +47 -0
- sqlce-0.1.1/docs/en/python.md +51 -0
- sqlce-0.1.1/docs/ru/cpp.md +47 -0
- sqlce-0.1.1/docs/ru/python.md +51 -0
- sqlce-0.1.1/main.py +112 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/pyproject.toml +9 -2
- sqlce-0.1.1/python/sqlce/__init__.py +6 -0
- sqlce-0.1.1/python/sqlce/__init__.pyi +7 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/python/sqlce/_sdf_native.pyi +13 -0
- sqlce-0.1.1/research/sdf_d3.py +90 -0
- sqlce-0.1.1/research/sdf_d4.py +94 -0
- sqlce-0.1.0/docs/4.0/ru/00-overview.md +0 -50
- sqlce-0.1.0/docs/4.0/ru/01-rows.md +0 -119
- sqlce-0.1.0/docs/4.0/ru/02-lob.md +0 -69
- sqlce-0.1.0/docs/4.0/ru/03-column-types.md +0 -80
- sqlce-0.1.0/docs/4.0/ru/04-catalog.md +0 -66
- sqlce-0.1.0/docs/4.0/ru/05-limitations.md +0 -50
- sqlce-0.1.0/docs/4.0/ru/catalog/00-schema.md +0 -94
- sqlce-0.1.0/docs/4.0/ru/catalog/01-row-layout.md +0 -107
- sqlce-0.1.0/docs/4.0/ru/catalog/02-classification.md +0 -32
- sqlce-0.1.0/docs/4.0/ru/catalog/03-status.md +0 -72
- sqlce-0.1.0/main.py +0 -76
- sqlce-0.1.0/python/sqlce/__init__.py +0 -4
- sqlce-0.1.0/python/sqlce/__init__.pyi +0 -5
- {sqlce-0.1.0 → sqlce-0.1.1}/.github/workflows/release.yml +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/.gitignore +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/CMakeLists.txt +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/LICENSE +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/bindings/CMakeLists.txt +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/bindings/src/value_convert.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/bindings/src/value_convert.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/application/ColumnSchema.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/ColumnDef.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/ColumnType.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/ColumnValue.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/DateTimeValue.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/Guid.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/IPageStorage.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/NumericValue.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/Row.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/domain/TableDef.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/infrastructure/BinaryReader.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/infrastructure/PageView.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/CatalogPageScanner.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/CatalogRow.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/CatalogRowDecoder.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/CatalogSchema.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/ICatalogPageScanner.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/ICatalogRowDecoder.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/ILobChainRegistry.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/IRowDecoder.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/ITableCatalogBuilder.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/LobChainRegistry.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/RowDecoder.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/TableCatalogBuilder.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/include/sdf/parsing/TextDecoder.hpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/domain/ColumnDef.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/domain/ColumnType.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/domain/ColumnValue.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/domain/DateTimeValue.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/domain/Guid.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/domain/NumericValue.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/domain/Row.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/domain/TableDef.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/infrastructure/BinaryReader.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/infrastructure/PageView.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/parsing/CatalogPageScanner.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/parsing/CatalogRow.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/parsing/CatalogRowDecoder.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/parsing/CatalogSchema.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/parsing/LobChainRegistry.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/parsing/RowDecoder.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/parsing/TableCatalogBuilder.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/src/parsing/TextDecoder.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/tests/CMakeLists.txt +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/core/tests/count_test.cpp +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/docs/CONVENTIONS.md +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/requirements.txt +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/research/catalog_parse/sdf_pages.py +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/research/catalog_parse/syscatalog.py +0 -0
- {sqlce-0.1.0 → sqlce-0.1.1}/research/sdf_reader.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: sqlce
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Cross-platform lib for reading SQL Server CE (.sdf)
|
|
5
5
|
Author-Email: boykopovar <boykopovar@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -27,21 +27,22 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
|
|
28
28
|
Анализ внутреннего устройства формата по декомпилированным компонентам SQL CE. Цель - предоставить кроссплатформенную и независимую от рантайма реализацию чтения `.sdf` и документацию формата.
|
|
29
29
|
|
|
30
|
-
## Структура
|
|
31
30
|
|
|
32
31
|
- `core/` - реализация парсера на C++
|
|
33
32
|
- `bindings/` - Биндинги для C++ библиотеки к другим языкам
|
|
34
33
|
- `python/sqlce/` - Python API
|
|
35
34
|
- `research/` - Экспериментальные скрипты
|
|
36
35
|
|
|
37
|
-
## Установка
|
|
38
36
|
|
|
39
37
|
```bash
|
|
40
38
|
pip install sqlce
|
|
41
39
|
```
|
|
42
40
|
|
|
43
|
-
[Документирование формата](docs/4.0/ru/00-overview.md)
|
|
44
41
|
|
|
45
|
-
Текущая [реализация](main.py) поддерживает чтение списка таблиц, структуры таблиц, содержимого записей. Использует c++.
|
|
42
|
+
Текущая [реализация](main.py) поддерживает чтение (поддерживается передача пароля) списка таблиц, структуры таблиц, содержимого записей. Использует c++.
|
|
43
|
+
|
|
44
|
+
[Документация](docs/ru/python.md)
|
|
45
|
+
|
|
46
|
+
[Documentation](docs/en/python.md)
|
|
46
47
|
|
|
47
48
|
[Соглашения по написанию кода](docs/CONVENTIONS.md)
|
|
@@ -4,21 +4,22 @@
|
|
|
4
4
|
|
|
5
5
|
Анализ внутреннего устройства формата по декомпилированным компонентам SQL CE. Цель - предоставить кроссплатформенную и независимую от рантайма реализацию чтения `.sdf` и документацию формата.
|
|
6
6
|
|
|
7
|
-
## Структура
|
|
8
7
|
|
|
9
8
|
- `core/` - реализация парсера на C++
|
|
10
9
|
- `bindings/` - Биндинги для C++ библиотеки к другим языкам
|
|
11
10
|
- `python/sqlce/` - Python API
|
|
12
11
|
- `research/` - Экспериментальные скрипты
|
|
13
12
|
|
|
14
|
-
## Установка
|
|
15
13
|
|
|
16
14
|
```bash
|
|
17
15
|
pip install sqlce
|
|
18
16
|
```
|
|
19
17
|
|
|
20
|
-
[Документирование формата](docs/4.0/ru/00-overview.md)
|
|
21
18
|
|
|
22
|
-
Текущая [реализация](main.py) поддерживает чтение списка таблиц, структуры таблиц, содержимого записей. Использует c++.
|
|
19
|
+
Текущая [реализация](main.py) поддерживает чтение (поддерживается передача пароля) списка таблиц, структуры таблиц, содержимого записей. Использует c++.
|
|
20
|
+
|
|
21
|
+
[Документация](docs/ru/python.md)
|
|
22
|
+
|
|
23
|
+
[Documentation](docs/en/python.md)
|
|
23
24
|
|
|
24
25
|
[Соглашения по написанию кода](docs/CONVENTIONS.md)
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
#include "sdf/application/ColumnSchema.hpp"
|
|
11
11
|
#include "sdf/application/SdfDatabase.hpp"
|
|
12
|
+
#include "sdf/domain/EncryptionMode.hpp"
|
|
12
13
|
#include "sdf/domain/Row.hpp"
|
|
13
14
|
|
|
14
15
|
#include "value_convert.hpp"
|
|
@@ -26,7 +27,9 @@ constexpr char ModuleDoc[] = "Native reader for SQL Server Compact (.sdf) databa
|
|
|
26
27
|
constexpr char DatabaseClassName[] = "SdfDatabase";
|
|
27
28
|
constexpr char DatabaseDoc[] = "Reads tables, schemas and rows from a .sdf database file.";
|
|
28
29
|
constexpr char InitDoc[] = "Open a .sdf file at the given path.";
|
|
30
|
+
constexpr char InitWithPasswordDoc[] = "Open a password-protected .sdf file, auto-detecting its encryption mode.";
|
|
29
31
|
constexpr char PathArgName[] = "path";
|
|
32
|
+
constexpr char PasswordArgName[] = "password";
|
|
30
33
|
constexpr char ListTablesName[] = "list_tables";
|
|
31
34
|
constexpr char ListTablesDoc[] = "Return the names of all tables in the database.";
|
|
32
35
|
constexpr char TableSchemaName[] = "table_schema";
|
|
@@ -44,6 +47,9 @@ constexpr char DeclaredSizeAttrName[] = "declared_size";
|
|
|
44
47
|
constexpr char PrecisionAttrName[] = "precision";
|
|
45
48
|
constexpr char ScaleAttrName[] = "scale";
|
|
46
49
|
|
|
50
|
+
constexpr char UnsupportedEncryptionModeErrorName[] = "UnsupportedEncryptionModeError";
|
|
51
|
+
constexpr char InvalidPasswordErrorName[] = "InvalidPasswordError";
|
|
52
|
+
|
|
47
53
|
py::dict RowToDict(const domain::Row& row)
|
|
48
54
|
{
|
|
49
55
|
py::dict result;
|
|
@@ -75,12 +81,40 @@ std::optional<int> OptionalByteToInt(std::optional<std::uint8_t> value)
|
|
|
75
81
|
return static_cast<int>(*value);
|
|
76
82
|
}
|
|
77
83
|
|
|
84
|
+
void RegisterExceptions(py::module_& module)
|
|
85
|
+
{
|
|
86
|
+
static const py::exception<domain::UnsupportedEncryptionModeException> unsupportedModeError(
|
|
87
|
+
module, UnsupportedEncryptionModeErrorName, PyExc_ValueError);
|
|
88
|
+
static const py::exception<domain::InvalidPasswordException> invalidPasswordError(
|
|
89
|
+
module, InvalidPasswordErrorName, PyExc_ValueError);
|
|
90
|
+
|
|
91
|
+
py::register_exception_translator([](std::exception_ptr lastException) {
|
|
92
|
+
try
|
|
93
|
+
{
|
|
94
|
+
if (lastException)
|
|
95
|
+
{
|
|
96
|
+
std::rethrow_exception(lastException);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (const domain::UnsupportedEncryptionModeException& error)
|
|
100
|
+
{
|
|
101
|
+
PyErr_SetString(unsupportedModeError.ptr(), error.what());
|
|
102
|
+
}
|
|
103
|
+
catch (const domain::InvalidPasswordException& error)
|
|
104
|
+
{
|
|
105
|
+
PyErr_SetString(invalidPasswordError.ptr(), error.what());
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
78
110
|
}
|
|
79
111
|
|
|
80
112
|
PYBIND11_MODULE(_sdf_native, module)
|
|
81
113
|
{
|
|
82
114
|
module.doc() = ModuleDoc;
|
|
83
115
|
|
|
116
|
+
RegisterExceptions(module);
|
|
117
|
+
|
|
84
118
|
py::class_<application::ColumnSchema>(module, SchemaClassName, SchemaDoc)
|
|
85
119
|
.def_property_readonly(
|
|
86
120
|
OrdinalAttrName,
|
|
@@ -103,6 +137,11 @@ PYBIND11_MODULE(_sdf_native, module)
|
|
|
103
137
|
|
|
104
138
|
py::class_<application::SdfDatabase>(module, DatabaseClassName, DatabaseDoc)
|
|
105
139
|
.def(py::init<const std::string&>(), py::arg(PathArgName), InitDoc)
|
|
140
|
+
.def(
|
|
141
|
+
py::init<const std::string&, const std::string&>(),
|
|
142
|
+
py::arg(PathArgName),
|
|
143
|
+
py::arg(PasswordArgName),
|
|
144
|
+
InitWithPasswordDoc)
|
|
106
145
|
.def(ListTablesName, &application::SdfDatabase::ListTables, ListTablesDoc)
|
|
107
146
|
.def(
|
|
108
147
|
TableSchemaName,
|
|
@@ -18,15 +18,19 @@ add_library(libsdf
|
|
|
18
18
|
src/domain/NumericValue.cpp
|
|
19
19
|
src/domain/Row.cpp
|
|
20
20
|
src/domain/TableDef.cpp
|
|
21
|
+
src/infrastructure/AesCbc.cpp
|
|
21
22
|
src/infrastructure/BinaryReader.cpp
|
|
22
23
|
src/infrastructure/FileStorage.cpp
|
|
23
24
|
src/infrastructure/PageView.cpp
|
|
25
|
+
src/infrastructure/Sha256.cpp
|
|
26
|
+
src/infrastructure/Sha512.cpp
|
|
24
27
|
src/parsing/CatalogPageScanner.cpp
|
|
25
28
|
src/parsing/CatalogRow.cpp
|
|
26
29
|
src/parsing/CatalogRowDecoder.cpp
|
|
27
30
|
src/parsing/CatalogSchema.cpp
|
|
28
31
|
src/parsing/LobChainRegistry.cpp
|
|
29
32
|
src/parsing/RowDecoder.cpp
|
|
33
|
+
src/parsing/SdfPageCipher.cpp
|
|
30
34
|
src/parsing/TableCatalogBuilder.cpp
|
|
31
35
|
src/parsing/TextDecoder.cpp
|
|
32
36
|
src/application/SdfDatabase.cpp
|
|
@@ -45,7 +49,7 @@ else()
|
|
|
45
49
|
target_compile_options(libsdf PRIVATE -Wall -Wextra)
|
|
46
50
|
endif()
|
|
47
51
|
|
|
48
|
-
add_executable(sdf_dump
|
|
52
|
+
add_executable(sdf_dump main.cpp)
|
|
49
53
|
target_link_libraries(sdf_dump PRIVATE libsdf)
|
|
50
54
|
|
|
51
55
|
if(MSVC)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#include <vector>
|
|
8
8
|
|
|
9
9
|
#include "sdf/application/ColumnSchema.hpp"
|
|
10
|
+
#include "sdf/domain/IPageCipher.hpp"
|
|
10
11
|
#include "sdf/domain/IPageStorage.hpp"
|
|
11
12
|
#include "sdf/domain/Row.hpp"
|
|
12
13
|
#include "sdf/domain/TableDef.hpp"
|
|
@@ -22,6 +23,7 @@ class SdfDatabase
|
|
|
22
23
|
{
|
|
23
24
|
public:
|
|
24
25
|
explicit SdfDatabase(const std::string& path);
|
|
26
|
+
SdfDatabase(const std::string& path, const std::string& password);
|
|
25
27
|
|
|
26
28
|
std::vector<std::string> ListTables() const;
|
|
27
29
|
std::vector<ColumnSchema> TableSchema(const std::string& tableName) const;
|
|
@@ -36,6 +38,10 @@ private:
|
|
|
36
38
|
|
|
37
39
|
std::map<std::string, domain::TableDef> _tables;
|
|
38
40
|
|
|
41
|
+
explicit SdfDatabase(std::unique_ptr<domain::IPageStorage> storage);
|
|
42
|
+
|
|
43
|
+
static std::unique_ptr<domain::IPageStorage> OpenStorage(const std::string& path, const std::string& password);
|
|
44
|
+
|
|
39
45
|
void AssignDataPages();
|
|
40
46
|
const domain::TableDef& RequireTable(const std::string& tableName) const;
|
|
41
47
|
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#ifndef SDF_DOMAIN_ENCRYPTION_MODE_HPP
|
|
2
|
+
#define SDF_DOMAIN_ENCRYPTION_MODE_HPP
|
|
3
|
+
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
#include <stdexcept>
|
|
6
|
+
#include <string>
|
|
7
|
+
|
|
8
|
+
namespace sdf::domain
|
|
9
|
+
{
|
|
10
|
+
|
|
11
|
+
enum class EncryptionMode : std::uint32_t
|
|
12
|
+
{
|
|
13
|
+
None = 0,
|
|
14
|
+
Rc4Sha1 = 1,
|
|
15
|
+
Aes128Sha1 = 2,
|
|
16
|
+
Aes128Sha256 = 3,
|
|
17
|
+
Aes256Sha512 = 4
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
class UnsupportedEncryptionModeException final : public std::runtime_error
|
|
21
|
+
{
|
|
22
|
+
public:
|
|
23
|
+
explicit UnsupportedEncryptionModeException(EncryptionMode mode)
|
|
24
|
+
: std::runtime_error("unsupported .sdf encryption mode: " + std::to_string(static_cast<std::uint32_t>(mode)))
|
|
25
|
+
, _mode(mode)
|
|
26
|
+
{
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
EncryptionMode Mode() const
|
|
30
|
+
{
|
|
31
|
+
return _mode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private:
|
|
35
|
+
EncryptionMode _mode;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
class InvalidPasswordException final : public std::runtime_error
|
|
39
|
+
{
|
|
40
|
+
public:
|
|
41
|
+
InvalidPasswordException() : std::runtime_error("password verification failed")
|
|
42
|
+
{
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#endif
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#ifndef SDF_DOMAIN_I_PAGE_CIPHER_HPP
|
|
2
|
+
#define SDF_DOMAIN_I_PAGE_CIPHER_HPP
|
|
3
|
+
|
|
4
|
+
#include <cstddef>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <span>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
namespace sdf::domain
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
class IPageCipher
|
|
13
|
+
{
|
|
14
|
+
public:
|
|
15
|
+
virtual ~IPageCipher() = default;
|
|
16
|
+
|
|
17
|
+
virtual bool VerifyPassword() const = 0;
|
|
18
|
+
virtual std::vector<std::uint8_t> DecryptPage(std::size_t pageNumber, std::span<const std::uint8_t> page) const = 0;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#endif
|
|
@@ -14,6 +14,14 @@ constexpr std::size_t LobPageHeaderLength = 16;
|
|
|
14
14
|
constexpr std::size_t SlotArrayBaseIndex = 1017;
|
|
15
15
|
constexpr std::size_t RowHeaderLength = 28;
|
|
16
16
|
|
|
17
|
+
constexpr std::size_t PlaintextHeaderLength = 16;
|
|
18
|
+
constexpr std::size_t Page0ModeOffset = 184;
|
|
19
|
+
constexpr std::size_t Page0VerifierOffset = 76;
|
|
20
|
+
constexpr std::size_t Page0VerifierLength = 96;
|
|
21
|
+
constexpr std::size_t Page0KeyParamOffset = 188;
|
|
22
|
+
constexpr std::size_t Page0KeyParamLength = 4;
|
|
23
|
+
constexpr std::size_t MaxPasswordLength = 40;
|
|
24
|
+
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
#endif
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#ifndef SDF_INFRASTRUCTURE_AES_CBC_HPP
|
|
2
|
+
#define SDF_INFRASTRUCTURE_AES_CBC_HPP
|
|
3
|
+
|
|
4
|
+
#include <array>
|
|
5
|
+
#include <cstddef>
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <span>
|
|
8
|
+
#include <vector>
|
|
9
|
+
|
|
10
|
+
namespace sdf::infrastructure
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
class AesCbcDecryptor
|
|
14
|
+
{
|
|
15
|
+
public:
|
|
16
|
+
explicit AesCbcDecryptor(std::span<const std::uint8_t> key, std::span<const std::uint8_t, 16> iv);
|
|
17
|
+
|
|
18
|
+
std::vector<std::uint8_t> Decrypt(std::span<const std::uint8_t> ciphertext) const;
|
|
19
|
+
|
|
20
|
+
private:
|
|
21
|
+
std::vector<std::uint32_t> _roundKeys;
|
|
22
|
+
std::size_t _roundCount;
|
|
23
|
+
std::array<std::uint8_t, 16> _iv;
|
|
24
|
+
|
|
25
|
+
void DecryptBlock(const std::uint8_t* in, std::uint8_t* out) const;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#endif
|
|
@@ -2,18 +2,23 @@
|
|
|
2
2
|
#define SDF_INFRASTRUCTURE_FILE_STORAGE_HPP
|
|
3
3
|
|
|
4
4
|
#include <cstdint>
|
|
5
|
+
#include <optional>
|
|
5
6
|
#include <string>
|
|
6
7
|
#include <vector>
|
|
7
8
|
|
|
9
|
+
#include "sdf/domain/IPageCipher.hpp"
|
|
8
10
|
#include "sdf/domain/IPageStorage.hpp"
|
|
9
11
|
|
|
10
12
|
namespace sdf::infrastructure
|
|
11
13
|
{
|
|
12
14
|
|
|
15
|
+
std::vector<std::uint8_t> ReadFirstPageRaw(const std::string& path);
|
|
16
|
+
|
|
13
17
|
class FileStorage final : public domain::IPageStorage
|
|
14
18
|
{
|
|
15
19
|
public:
|
|
16
20
|
explicit FileStorage(const std::string& path);
|
|
21
|
+
FileStorage(const std::string& path, const domain::IPageCipher& cipher);
|
|
17
22
|
|
|
18
23
|
std::size_t PageCount() const override;
|
|
19
24
|
std::span<const std::uint8_t> PageBytes(std::size_t pageNumber) const override;
|
|
@@ -21,6 +26,8 @@ public:
|
|
|
21
26
|
private:
|
|
22
27
|
std::vector<std::uint8_t> _fileBytes;
|
|
23
28
|
std::size_t _pageCount;
|
|
29
|
+
|
|
30
|
+
void Load(const std::string& path);
|
|
24
31
|
};
|
|
25
32
|
|
|
26
33
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#ifndef SDF_INFRASTRUCTURE_SHA256_HPP
|
|
2
|
+
#define SDF_INFRASTRUCTURE_SHA256_HPP
|
|
3
|
+
|
|
4
|
+
#include <array>
|
|
5
|
+
#include <cstddef>
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <span>
|
|
8
|
+
|
|
9
|
+
namespace sdf::infrastructure
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
std::array<std::uint8_t, 32> Sha256(std::span<const std::uint8_t> message);
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#endif
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#ifndef SDF_INFRASTRUCTURE_SHA512_HPP
|
|
2
|
+
#define SDF_INFRASTRUCTURE_SHA512_HPP
|
|
3
|
+
|
|
4
|
+
#include <array>
|
|
5
|
+
#include <cstddef>
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <span>
|
|
8
|
+
|
|
9
|
+
namespace sdf::infrastructure
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
std::array<std::uint8_t, 64> Sha512(std::span<const std::uint8_t> message);
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#endif
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#ifndef SDF_PARSING_SDF_PAGE_CIPHER_HPP
|
|
2
|
+
#define SDF_PARSING_SDF_PAGE_CIPHER_HPP
|
|
3
|
+
|
|
4
|
+
#include <array>
|
|
5
|
+
#include <cstddef>
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <span>
|
|
8
|
+
#include <string>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
#include "sdf/domain/EncryptionMode.hpp"
|
|
12
|
+
#include "sdf/domain/IPageCipher.hpp"
|
|
13
|
+
|
|
14
|
+
namespace sdf::parsing
|
|
15
|
+
{
|
|
16
|
+
|
|
17
|
+
class SdfPageCipher final : public domain::IPageCipher
|
|
18
|
+
{
|
|
19
|
+
public:
|
|
20
|
+
SdfPageCipher(std::span<const std::uint8_t> page0, std::string password);
|
|
21
|
+
|
|
22
|
+
static domain::EncryptionMode ReadMode(std::span<const std::uint8_t> page0);
|
|
23
|
+
|
|
24
|
+
bool VerifyPassword() const override;
|
|
25
|
+
std::vector<std::uint8_t> DecryptPage(std::size_t pageNumber, std::span<const std::uint8_t> page) const override;
|
|
26
|
+
|
|
27
|
+
private:
|
|
28
|
+
domain::EncryptionMode _mode;
|
|
29
|
+
std::string _password;
|
|
30
|
+
std::vector<std::uint8_t> _passwordUtf16Le;
|
|
31
|
+
std::vector<std::uint8_t> _page0Ciphertext;
|
|
32
|
+
std::array<std::uint8_t, 4> _page0KeyParam;
|
|
33
|
+
|
|
34
|
+
std::vector<std::uint8_t> DecryptPage0(std::span<const std::uint8_t> page0) const;
|
|
35
|
+
std::vector<std::uint8_t> DeriveKey(std::span<const std::uint8_t> keyParam) const;
|
|
36
|
+
std::vector<std::uint8_t> HashPasswordWith(std::span<const std::uint8_t> keyParam) const;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#endif
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#include <algorithm>
|
|
2
2
|
#include <filesystem>
|
|
3
3
|
#include <iostream>
|
|
4
|
+
#include <memory>
|
|
4
5
|
#include <vector>
|
|
5
6
|
|
|
6
|
-
#include "sdf/application/SdfDatabase.hpp"
|
|
7
|
+
#include "include/sdf/application/SdfDatabase.hpp"
|
|
8
|
+
#include "include/sdf/domain/EncryptionMode.hpp"
|
|
7
9
|
|
|
8
10
|
namespace
|
|
9
11
|
{
|
|
@@ -71,12 +73,28 @@ void PrintTableRows(const std::vector<std::string>& columnNames, const std::vect
|
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
void DumpFile(const std::filesystem::path& sdfPath)
|
|
76
|
+
void DumpFile(const std::filesystem::path& sdfPath, const std::string& password)
|
|
75
77
|
{
|
|
76
78
|
std::cout << "\n" << sdfPath.filename().string() << "\n";
|
|
77
79
|
|
|
78
|
-
sdf::application::SdfDatabase db
|
|
79
|
-
|
|
80
|
+
std::unique_ptr<sdf::application::SdfDatabase> db;
|
|
81
|
+
try
|
|
82
|
+
{
|
|
83
|
+
db = password.empty() ? std::make_unique<sdf::application::SdfDatabase>(sdfPath.string())
|
|
84
|
+
: std::make_unique<sdf::application::SdfDatabase>(sdfPath.string(), password);
|
|
85
|
+
}
|
|
86
|
+
catch (const sdf::domain::UnsupportedEncryptionModeException& error)
|
|
87
|
+
{
|
|
88
|
+
std::cout << "skipped: " << error.what() << "\n";
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
catch (const sdf::domain::InvalidPasswordException& error)
|
|
92
|
+
{
|
|
93
|
+
std::cout << "skipped: " << error.what() << "\n";
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
std::vector<std::string> tableNames = db->ListTables();
|
|
80
98
|
|
|
81
99
|
if (tableNames.empty())
|
|
82
100
|
{
|
|
@@ -88,7 +106,7 @@ void DumpFile(const std::filesystem::path& sdfPath)
|
|
|
88
106
|
{
|
|
89
107
|
std::cout << "\ntable: " << tableName << "\n";
|
|
90
108
|
|
|
91
|
-
for (const sdf::application::ColumnSchema& column : db
|
|
109
|
+
for (const sdf::application::ColumnSchema& column : db->TableSchema(tableName))
|
|
92
110
|
{
|
|
93
111
|
std::cout << " " << column.ordinal << ". " << column.name << " " << column.typeName
|
|
94
112
|
<< " size=" << column.declaredSize;
|
|
@@ -100,7 +118,7 @@ void DumpFile(const std::filesystem::path& sdfPath)
|
|
|
100
118
|
std::cout << "\n";
|
|
101
119
|
}
|
|
102
120
|
|
|
103
|
-
const std::vector<sdf::domain::Row> rows = db
|
|
121
|
+
const std::vector<sdf::domain::Row> rows = db->ReadTable(tableName);
|
|
104
122
|
if (rows.empty())
|
|
105
123
|
{
|
|
106
124
|
std::cout << " (no rows)\n";
|
|
@@ -120,36 +138,58 @@ void DumpFile(const std::filesystem::path& sdfPath)
|
|
|
120
138
|
|
|
121
139
|
int main(int argc, char** argv)
|
|
122
140
|
{
|
|
123
|
-
|
|
141
|
+
std::filesystem::path directory("research/raw/examples");
|
|
142
|
+
std::string password;
|
|
124
143
|
|
|
125
|
-
|
|
126
|
-
std::cout << "looking for: " << std::filesystem::absolute(directory) << "\n";
|
|
127
|
-
|
|
128
|
-
if (!std::filesystem::is_directory(directory))
|
|
144
|
+
for (int i = 1; i < argc; ++i)
|
|
129
145
|
{
|
|
130
|
-
std::
|
|
131
|
-
|
|
146
|
+
const std::string argument = argv[i];
|
|
147
|
+
if (argument == "--password" && i + 1 < argc)
|
|
148
|
+
{
|
|
149
|
+
password = argv[++i];
|
|
150
|
+
}
|
|
151
|
+
else
|
|
152
|
+
{
|
|
153
|
+
directory = std::filesystem::path(argument);
|
|
154
|
+
}
|
|
132
155
|
}
|
|
133
156
|
|
|
134
|
-
std::
|
|
135
|
-
|
|
157
|
+
std::cout << "current working directory: " << std::filesystem::current_path() << "\n";
|
|
158
|
+
|
|
159
|
+
std::vector<std::pair<std::filesystem::path, std::string>> directoriesToScan;
|
|
160
|
+
directoriesToScan.emplace_back(directory, password);
|
|
161
|
+
directoriesToScan.emplace_back(directory / "protected", password.empty() ? "secret123" : password);
|
|
162
|
+
|
|
163
|
+
for (const auto& [scanDirectory, scanPassword] : directoriesToScan)
|
|
136
164
|
{
|
|
137
|
-
|
|
165
|
+
std::cout << "looking for: " << std::filesystem::absolute(scanDirectory) << "\n";
|
|
166
|
+
|
|
167
|
+
if (!std::filesystem::is_directory(scanDirectory))
|
|
138
168
|
{
|
|
139
|
-
|
|
169
|
+
std::cerr << "directory not found: " << scanDirectory << "\n";
|
|
170
|
+
continue;
|
|
140
171
|
}
|
|
141
|
-
}
|
|
142
|
-
std::sort(sdfFiles.begin(), sdfFiles.end());
|
|
143
172
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
173
|
+
std::vector<std::filesystem::path> sdfFiles;
|
|
174
|
+
for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(scanDirectory))
|
|
175
|
+
{
|
|
176
|
+
if (entry.path().extension() == ".sdf")
|
|
177
|
+
{
|
|
178
|
+
sdfFiles.push_back(entry.path());
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
std::sort(sdfFiles.begin(), sdfFiles.end());
|
|
149
182
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
183
|
+
if (sdfFiles.empty())
|
|
184
|
+
{
|
|
185
|
+
std::cout << "no .sdf files found in " << scanDirectory << "\n";
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
for (const std::filesystem::path& sdfFile : sdfFiles)
|
|
190
|
+
{
|
|
191
|
+
DumpFile(sdfFile, scanPassword);
|
|
192
|
+
}
|
|
153
193
|
}
|
|
154
194
|
|
|
155
195
|
return 0;
|
|
@@ -8,13 +8,34 @@
|
|
|
8
8
|
#include "sdf/parsing/CatalogRowDecoder.hpp"
|
|
9
9
|
#include "sdf/parsing/LobChainRegistry.hpp"
|
|
10
10
|
#include "sdf/parsing/RowDecoder.hpp"
|
|
11
|
+
#include "sdf/parsing/SdfPageCipher.hpp"
|
|
11
12
|
#include "sdf/parsing/TableCatalogBuilder.hpp"
|
|
12
13
|
|
|
13
14
|
namespace sdf::application
|
|
14
15
|
{
|
|
15
16
|
|
|
16
|
-
SdfDatabase::SdfDatabase(const std::string& path)
|
|
17
|
-
|
|
17
|
+
SdfDatabase::SdfDatabase(const std::string& path) : SdfDatabase(OpenStorage(path, std::string()))
|
|
18
|
+
{
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
SdfDatabase::SdfDatabase(const std::string& path, const std::string& password) : SdfDatabase(OpenStorage(path, password))
|
|
22
|
+
{
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
std::unique_ptr<domain::IPageStorage> SdfDatabase::OpenStorage(const std::string& path, const std::string& password)
|
|
26
|
+
{
|
|
27
|
+
if (password.empty())
|
|
28
|
+
{
|
|
29
|
+
return std::make_unique<infrastructure::FileStorage>(path);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const std::vector<std::uint8_t> firstPage = infrastructure::ReadFirstPageRaw(path);
|
|
33
|
+
const parsing::SdfPageCipher cipher(firstPage, password);
|
|
34
|
+
return std::make_unique<infrastructure::FileStorage>(path, cipher);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
SdfDatabase::SdfDatabase(std::unique_ptr<domain::IPageStorage> storage)
|
|
38
|
+
: _storage(std::move(storage))
|
|
18
39
|
, _pageScanner(std::make_shared<parsing::CatalogPageScanner>())
|
|
19
40
|
, _tableCatalogBuilder(
|
|
20
41
|
std::make_shared<parsing::TableCatalogBuilder>(_pageScanner, std::make_shared<parsing::CatalogRowDecoder>()))
|