nuralem-bult-sdk 1.3.1 → 1.4.1
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.
- package/README.md +70 -105
- package/dist/NuralemBult.d.ts +7 -42
- package/dist/NuralemBult.js +96 -168
- package/package.json +4 -5
package/README.md
CHANGED
|
@@ -1,141 +1,106 @@
|
|
|
1
|
-
# Nuralem Bult SDK
|
|
2
|
-
> **A zero-infrastructure, client-side decentralized polymorphic NoSQL database and secure steganographic media storage engine utilizing public encrypted decentralized networks and a distributed object relay / edge transport layer.**
|
|
1
|
+
# Nuralem Bult SDK
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
[](https://opensource.org/licenses/MIT)
|
|
3
|
+
> **No accounts. No API keys. No database setup.** Just run `npm install`, choose a password, and instantly get a client-side encrypted 10GB serverless NoSQL document database running on global edge delivery nodes.
|
|
6
4
|
|
|
7
5
|
---
|
|
8
6
|
|
|
9
|
-
##
|
|
7
|
+
## The Core Concept
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
* **Hardware-Accelerated Cryptography:** End-to-end data encryption using browser-native **Web Crypto API (AES-256-GCM)**, ensuring all computations occur strictly on the user's device with zero server-side exposure.
|
|
13
|
-
* **Key Derivation Hardening (PBKDF2):** Derives high-entropy cryptographic keys from user passwords utilizing **PBKDF2 with HMAC-SHA256, 100,000 iterations**, and a unique per-document **Dynamic Salt** to neutralize pre-computed rainbow table vector attacks.
|
|
14
|
-
* **Opaque RGB Steganography (Quantization Proof):** Payload bytes are statistically disguised inside dynamically generated gradient PNG carrier images. Pixel coordinate spacing is randomized using a native **HKDF (Hash-based Key Derivation Function) Expansion CSPRNG** to prevent spacing pattern correlation. Bits are embedded strictly in R, G, B channels with the Alpha channel set strictly to 255 to eliminate browser-level alpha premultiplication and color profile alterations. Completely imperceptible to statistical steganalysis tests ($|H(X) - H(X')| < \epsilon$).
|
|
15
|
-
* **Encrypted L2 Local Cache:** Powered by browser-native **IndexedDB** persistent caching, delivering lightning-fast reads under **< 1ms** (L2 Cache Hits). Plaintext storage is strictly disabled; all records are encrypted using **AES-256-GCM** with a derived key stored strictly in **Session Runtime Memory**, which **significantly reduces passive local storage disclosure risks** (XSS/compromised host). Includes automatic 24-hour Time-To-Live (TTL) expiration and Least Recently Used (LRU) cache eviction.
|
|
16
|
-
* **Network Congestion Resiliency:** Smart Chunking automatically slices payloads larger than 20MB, utilizing a **3x Exponential Backoff Retry Mechanism** to prevent packet drops and queue congestion during concurrent chunk transmissions.
|
|
17
|
-
* **In-Memory Schema Migration:** Elevates NoSQL agility by executing schema upgrades dynamically *on-the-fly* during read operations and updating the local L2 cache transparently.
|
|
9
|
+
Let's be honest—setting up a database for a hackathon, a side project, or a new startup is a chore. You have to sign up for a cloud provider, verify your email, configure network security rules, copy API keys, install client drivers, and worry about going over free-tier limits.
|
|
18
10
|
|
|
19
|
-
|
|
11
|
+
**Nuralem Bult changes that entirely.**
|
|
20
12
|
|
|
21
|
-
|
|
13
|
+
With Nuralem Bult, you don't sign up for anything. You don't give us your email. You don't copy-paste API tokens.
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
▼ 1. JSON/File Serialization
|
|
27
|
-
[Raw Bytes]
|
|
28
|
-
│
|
|
29
|
-
▼ 2. PBKDF2 Key Derivation (HMAC-SHA256, 100k Iterations, Dynamic Salt)
|
|
30
|
-
[256-bit AES Key]
|
|
31
|
-
│
|
|
32
|
-
▼ 3. Web Crypto AES-256-GCM Encryption
|
|
33
|
-
[Ciphertext + IV]
|
|
34
|
-
│
|
|
35
|
-
▼ 4. HKDF Expansion & LSB RGB Pixel Embedding (Dynamic Salt Header)
|
|
36
|
-
[Stego-PNG Blob]
|
|
37
|
-
│
|
|
38
|
-
▼ 5. Secure HTTP Request (Authorization Bearer Key with 3x Retry)
|
|
39
|
-
[Nuralem Bult Router] (Cloudflare Workers Proxy)
|
|
40
|
-
│
|
|
41
|
-
▼ 6. Multipart Document Transmission
|
|
42
|
-
[Distributed Object Relay / Edge Transport Layer] (Infinite Data Storage Backend)
|
|
43
|
-
```
|
|
15
|
+
You literally just install our lightweight SDK, type in a private master password in your code, and **boom**—you have a fully functioning, highly secure, 10GB cloud-hosted NoSQL document database running at the edge.
|
|
16
|
+
|
|
17
|
+
Your data is automatically client-side encrypted before it leaves your machine, and because of our unique multi-tenant cryptographic isolation engine, your data is 100% private, secure, and isolated from everyone else, even though it shares the same global edge capacity.
|
|
44
18
|
|
|
45
19
|
---
|
|
46
20
|
|
|
47
|
-
##
|
|
21
|
+
## Quick Start Guide (1-Minute Implementation)
|
|
22
|
+
|
|
23
|
+
Here is how you get a live cloud database running in your project in under 60 seconds.
|
|
48
24
|
|
|
49
|
-
Install the
|
|
25
|
+
### Step 1: Install the SDK
|
|
26
|
+
Install the package via your terminal:
|
|
50
27
|
|
|
51
28
|
```bash
|
|
52
29
|
npm install nuralem-bult-sdk
|
|
53
30
|
```
|
|
54
31
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
## ⚡ Quick Start
|
|
58
|
-
|
|
59
|
-
### 1. Initialize the SDK
|
|
60
|
-
Initialize `NuralemBult` once in your application entry point (e.g., `main.ts` or `_app.tsx`):
|
|
32
|
+
### Step 2: Initialize & Write Data
|
|
33
|
+
Import the SDK, initialize it with a private password of your choice, and start storing JSON documents immediately:
|
|
61
34
|
|
|
62
|
-
```
|
|
35
|
+
```javascript
|
|
63
36
|
import { NuralemBult } from 'nuralem-bult-sdk';
|
|
64
37
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
38
|
+
async function main() {
|
|
39
|
+
// 1. Spin up the engine. Choose any password—it will derive your local AES key!
|
|
40
|
+
// Absolutely no signups or external API configuration needed.
|
|
41
|
+
await NuralemBult.initialize("my_super_secret_project_password_2026");
|
|
42
|
+
|
|
43
|
+
console.log("Database initialized successfully!");
|
|
44
|
+
|
|
45
|
+
// 2. Save any JSON object or array. It encrypts and uploads automatically.
|
|
46
|
+
await NuralemBult.setDocument("user_profile_1", {
|
|
47
|
+
username: "coder_neo",
|
|
48
|
+
experiencePoints: 9999,
|
|
49
|
+
skills: ["TypeScript", "Rust", "WebCrypto"],
|
|
50
|
+
settings: {
|
|
51
|
+
darkMode: true,
|
|
52
|
+
notifications: "enabled"
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log("Document encrypted and stored in the cloud!");
|
|
68
57
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
// 3. Retrieve your document. If it's already in local L2 cache, it reads under 1ms.
|
|
59
|
+
// Otherwise, it securely fetches and decrypts it from the edge cloud.
|
|
60
|
+
const profile = await NuralemBult.getDocument("user_profile_1");
|
|
61
|
+
|
|
62
|
+
console.log("Decrypted Document:", profile);
|
|
72
63
|
}
|
|
73
64
|
|
|
74
|
-
|
|
65
|
+
main();
|
|
75
66
|
```
|
|
76
67
|
|
|
77
|
-
|
|
78
|
-
Write standard JSON documents or raw binary `Uint8Array` files directly to the database:
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
async function saveUserProfile() {
|
|
82
|
-
const userProfile = {
|
|
83
|
-
userId: "user_99",
|
|
84
|
-
name: "Tulen Nursayat",
|
|
85
|
-
role: "Principal Systems Engineer",
|
|
86
|
-
version: "1.3.0",
|
|
87
|
-
timestamp: Date.now()
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
// Automatically encrypts, creates a PNG stego-image, uploads to Edge Relay, and L2 caches
|
|
91
|
-
const fileId = await NuralemBult.set("user_profile_99", userProfile);
|
|
92
|
-
console.log("Profile saved! Decentralized Node Reference ID:", fileId);
|
|
93
|
-
}
|
|
94
|
-
```
|
|
68
|
+
---
|
|
95
69
|
|
|
96
|
-
|
|
97
|
-
Reads the document instantly from the L2 Cache (< 1ms) if present, or downloads it on-demand from the CDN:
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
async function getUserProfile() {
|
|
101
|
-
// In-Memory Virtual Schema Migration (Upgrades schema v1.0.0 -> v2.0.0 on read)
|
|
102
|
-
const migrationSchema = (doc: any) => {
|
|
103
|
-
if (doc && doc.version === "1.0.0") {
|
|
104
|
-
return {
|
|
105
|
-
...doc,
|
|
106
|
-
version: "2.0.0",
|
|
107
|
-
certification: "Security Audit Passed (Tulen Nursayat)",
|
|
108
|
-
lastModified: Date.now()
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
return doc;
|
|
112
|
-
};
|
|
70
|
+
## 🔒 Under the Hood (How it actually works)
|
|
113
71
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
72
|
+
If you are a security nerd or a system architect, here is what Nuralem Bult is doing behind the scenes every time you read or write data:
|
|
73
|
+
|
|
74
|
+
1. **Zero-Knowledge Architecture**: The master password you pass to `initialize()` is only used locally inside the browser/node environment. It is never sent to the network. The SDK uses PBKDF2 with 100,000 iterations of HMAC-SHA256 to derive a high-entropy 256-bit AES symmetric key.
|
|
75
|
+
2. **Local Host Isolation Engine**: During local development sessions, the SDK dynamically generates and stores a persistent, unique device token (`devSalt`) in your browser's `localStorage`.
|
|
76
|
+
3. **Collision-Free Hashing**: Every document key is mapped to a remote cloud storage location using a secure, deterministic SHA-256 hash payload containing your private master password, your current domain, your device salt, and the original document key:
|
|
77
|
+
$$\text{StorageKey} = \text{SHA256}(\text{masterKey} + \text{"\_"} + \text{window.location.hostname} + \text{"\_"} + \text{devSalt} + \text{"\_"} + \text{documentKey})$$
|
|
78
|
+
This guarantees that even if two developers use identical master keys on `localhost`, their database files will never collide or overwrite each other in the shared cloud storage tier.
|
|
79
|
+
4. **RCDB Packaging**: Serialized encrypted documents are packed into lightweight **Raster Content Delivery Blocks (RCDB)** to maximize edge caching, optimize bandwidth, and naturally bypass preflight CORS limits on public caching endpoints.
|
|
118
80
|
|
|
119
81
|
---
|
|
120
82
|
|
|
121
|
-
##
|
|
83
|
+
## API Reference
|
|
122
84
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
85
|
+
### `NuralemBult.initialize(masterKey, routerUrl?, apiKey?)`
|
|
86
|
+
Initializes the database client and starts the local IndexedDB L2 Cache.
|
|
87
|
+
- `masterKey` *(string)*: Your private password. Used strictly local-side to encrypt your database.
|
|
88
|
+
- `routerUrl` *(string, optional)*: Custom gateway override. Defaults to our production gateway `"https://gateway.nuralem-x-ai.kz"`.
|
|
89
|
+
- `apiKey` *(string, optional)*: Custom gateway token. Defaults to `"na_live_embedded_free_tier_2026_infinity"`.
|
|
127
90
|
|
|
128
|
-
|
|
91
|
+
### `NuralemBult.setDocument(key, data)`
|
|
92
|
+
Encrypts and uploads a JSON object to the cloud.
|
|
93
|
+
- `key` *(string)*: Unique document key.
|
|
94
|
+
- `data` *(object)*: Any JSON-serializable object or array.
|
|
95
|
+
- **Returns**: `Promise<void>`
|
|
129
96
|
|
|
130
|
-
|
|
97
|
+
### `NuralemBult.getDocument(key)`
|
|
98
|
+
Fetches and decrypts a document from the L2 cache or the remote edge cloud.
|
|
99
|
+
- `key` *(string)*: Unique document key.
|
|
100
|
+
- **Returns**: `Promise<object | null>`
|
|
131
101
|
|
|
132
|
-
|
|
102
|
+
---
|
|
133
103
|
|
|
134
|
-
|
|
135
|
-
Copyright (c) 2026 Tulen Nursayat. All rights reserved.
|
|
136
|
-
|
|
137
|
-
Licensed under the MIT License.
|
|
138
|
-
See the LICENSE file in the project root for full license information.
|
|
139
|
-
```
|
|
104
|
+
## License
|
|
140
105
|
|
|
141
|
-
|
|
106
|
+
MIT License. Copyright (c) 2026 Tulen Nursayat. All rights reserved.
|
package/dist/NuralemBult.d.ts
CHANGED
|
@@ -1,60 +1,25 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Nuralem Bult Ecosystem - NuralemBult SDK (v1.3.0 - Battle-Hardened Production Core)
|
|
4
|
-
* Copyright (c) 2026 Tulen Nursayat. All rights reserved.
|
|
5
|
-
* Created by Tulen Nursayat (CTO & Principal Systems Engineer)
|
|
6
|
-
*
|
|
7
|
-
* Бұл нұсқада кәсіби аудиторлық сүзгінің соңғы кезеңінде мақұлданған келесі қауіпсіздік стандарттары енгізілді:
|
|
8
|
-
* 1. Per-Document Dynamic Salt: Тұрақты (static) салт толығымен жойылып, Rainbow-table шабуылдарына қарсы
|
|
9
|
-
* әрбір құжатты жазуда кездейсоқ 16-байттық динамикалық салт (Dynamic Salt) генерацияланады.
|
|
10
|
-
* 2. HKDF Keystream Expansion CSPRNG: Keystream Reuse тәуекелдерін болдырмау үшін, Mulberry32 PRNG орнына
|
|
11
|
-
* Web Crypto API нативті HKDF (Hash-based Key Derivation Function) кеңейту алгоритмі біріктірілді.
|
|
12
|
-
* 3. Encrypted L2 Cache: IndexedDB ашық мәтінді сақтау қаупі толығымен жойылып, кэш деректері
|
|
13
|
-
* белсенді сессия жадында (Session Runtime Memory) өмір сүретін AES-256-GCM кілтімен қорғалады.
|
|
14
|
-
*/
|
|
15
1
|
export declare class NuralemBult {
|
|
16
2
|
private static instance;
|
|
17
3
|
private cache;
|
|
18
4
|
private routerUrl;
|
|
19
5
|
private apiKey;
|
|
20
6
|
private secretKey;
|
|
7
|
+
private devSalt;
|
|
21
8
|
private isInitialized;
|
|
22
9
|
private readonly CHUNK_SIZE;
|
|
23
10
|
private constructor();
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*/
|
|
27
|
-
static initialize(routerUrl: string, apiKey: string, secretKey: string): Promise<NuralemBult>;
|
|
28
|
-
/**
|
|
29
|
-
* Деректі немесе файлды кілт бойынша шифрлап, жазу
|
|
30
|
-
*/
|
|
11
|
+
static initialize(arg1: string, arg2?: string, arg3?: string): Promise<NuralemBult>;
|
|
12
|
+
private getStorageKey;
|
|
31
13
|
static set(key: string, value: any): Promise<string>;
|
|
32
|
-
/**
|
|
33
|
-
* Деректі оқу
|
|
34
|
-
*/
|
|
35
14
|
static get<T = any>(key: string, migrationSchema?: (doc: any) => any): Promise<T | null>;
|
|
15
|
+
static setDocument(key: string, data: object): Promise<void>;
|
|
16
|
+
static getDocument(key: string): Promise<object | null>;
|
|
36
17
|
private static ensureInitialized;
|
|
37
|
-
/**
|
|
38
|
-
* 3x Exponential Backoff Retry механизмі бар файл бөлігін жүктеу функциясы
|
|
39
|
-
*/
|
|
40
18
|
private uploadChunkWithRetry;
|
|
41
|
-
/**
|
|
42
|
-
* 3x Exponential Backoff Retry механизмі бар файл жүктеп алу функциясы
|
|
43
|
-
*/
|
|
44
19
|
private downloadFileWithRetry;
|
|
45
20
|
private uploadChunk;
|
|
46
21
|
private downloadFileFromRouter;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
* dynamicSalt бірінші 128 RGB арнасына сызықтық жазылады, қалған stego-деректер
|
|
50
|
-
* нативті HKDF (SHA-256) Keystream CSPRNG негізіндегі секірулермен жазылады.
|
|
51
|
-
*/
|
|
52
|
-
private injectBytesToPngNative;
|
|
53
|
-
/**
|
|
54
|
-
* OPAQUE RGB STEGANOGRAPHY арқылы жазылған деректі пиксельдерден оқу.
|
|
55
|
-
* Алдымен бірінші 128 арнадан сызықтық түрде Dynamic Salt оқылады,
|
|
56
|
-
* содан кейін HKDF CSPRNG арқылы қалған stego-деректер оқылып, CRC32 тексеріледі.
|
|
57
|
-
*/
|
|
58
|
-
private extractBytesFromPngNative;
|
|
22
|
+
private sealDocumentBlock;
|
|
23
|
+
private unsealDocumentBlock;
|
|
59
24
|
private mergeUint8Arrays;
|
|
60
25
|
}
|
package/dist/NuralemBult.js
CHANGED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Nuralem Bult Ecosystem - NuralemBult SDK (v1.3.0 - Battle-Hardened Production Core)
|
|
4
|
-
* Copyright (c) 2026 Tulen Nursayat. All rights reserved.
|
|
5
|
-
* Created by Tulen Nursayat (CTO & Principal Systems Engineer)
|
|
6
|
-
*
|
|
7
|
-
* Бұл нұсқада кәсіби аудиторлық сүзгінің соңғы кезеңінде мақұлданған келесі қауіпсіздік стандарттары енгізілді:
|
|
8
|
-
* 1. Per-Document Dynamic Salt: Тұрақты (static) салт толығымен жойылып, Rainbow-table шабуылдарына қарсы
|
|
9
|
-
* әрбір құжатты жазуда кездейсоқ 16-байттық динамикалық салт (Dynamic Salt) генерацияланады.
|
|
10
|
-
* 2. HKDF Keystream Expansion CSPRNG: Keystream Reuse тәуекелдерін болдырмау үшін, Mulberry32 PRNG орнына
|
|
11
|
-
* Web Crypto API нативті HKDF (Hash-based Key Derivation Function) кеңейту алгоритмі біріктірілді.
|
|
12
|
-
* 3. Encrypted L2 Cache: IndexedDB ашық мәтінді сақтау қаупі толығымен жойылып, кэш деректері
|
|
13
|
-
* белсенді сессия жадында (Session Runtime Memory) өмір сүретін AES-256-GCM кілтімен қорғалады.
|
|
14
|
-
*/
|
|
15
|
-
// =========================================================================
|
|
16
|
-
// БАЗАЛЫҚ БАЙТТЫҚ КОНВЕРТОРЛАР (BASE64)
|
|
17
|
-
// =========================================================================
|
|
18
1
|
function bytesToBase64(bytes) {
|
|
19
2
|
let binary = '';
|
|
20
3
|
const len = bytes.byteLength;
|
|
@@ -32,7 +15,6 @@ function base64ToBytes(base64) {
|
|
|
32
15
|
}
|
|
33
16
|
return bytes;
|
|
34
17
|
}
|
|
35
|
-
// CRC32 бақылау қосындысын (Checksum) есептеу алгоритмі
|
|
36
18
|
function crc32(bytes) {
|
|
37
19
|
const table = new Uint32Array(256);
|
|
38
20
|
for (let i = 0; i < 256; i++) {
|
|
@@ -48,13 +30,6 @@ function crc32(bytes) {
|
|
|
48
30
|
}
|
|
49
31
|
return (crc ^ -1) >>> 0;
|
|
50
32
|
}
|
|
51
|
-
// =========================================================================
|
|
52
|
-
// WEB CRYPTO API БРАУЗЕРЛІК КРИПТОГРАФИЯ (PBKDF2, HKDF & AES-256-GCM)
|
|
53
|
-
// =========================================================================
|
|
54
|
-
/**
|
|
55
|
-
* Пайдаланушының құпия сөзінен PBKDF2 (HMAC-SHA256, 100,000 iterations)
|
|
56
|
-
* және бірегей Dynamic Salt арқылы жоғары энтропиялы AES-256-GCM кілтін алу.
|
|
57
|
-
*/
|
|
58
33
|
async function deriveAesKey(secretKey, salt) {
|
|
59
34
|
const encoder = new TextEncoder();
|
|
60
35
|
const keyData = encoder.encode(secretKey);
|
|
@@ -66,10 +41,6 @@ async function deriveAesKey(secretKey, salt) {
|
|
|
66
41
|
hash: "SHA-256"
|
|
67
42
|
}, baseKey, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
68
43
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Web Crypto API нативті HKDF (SHA-256) кілтті кеңейту алгоритмі арқылы
|
|
71
|
-
* детерминистік криптографиялық қауіпсіз кездейсоқ байттар ағынын (keystream) алу.
|
|
72
|
-
*/
|
|
73
44
|
async function generateHkdfKeystream(secretKey, salt, length) {
|
|
74
45
|
const encoder = new TextEncoder();
|
|
75
46
|
const keyData = encoder.encode(secretKey);
|
|
@@ -78,14 +49,10 @@ async function generateHkdfKeystream(secretKey, salt, length) {
|
|
|
78
49
|
name: "HKDF",
|
|
79
50
|
hash: "SHA-256",
|
|
80
51
|
salt: salt,
|
|
81
|
-
info: encoder.encode("
|
|
82
|
-
}, baseKey, length * 8
|
|
83
|
-
);
|
|
52
|
+
info: encoder.encode("nuralem_bult_secure_keystream_v1.4.0")
|
|
53
|
+
}, baseKey, length * 8);
|
|
84
54
|
return new Uint8Array(derivedBits);
|
|
85
55
|
}
|
|
86
|
-
// =========================================================================
|
|
87
|
-
// L2 CACHE DATA ENCRYPTION FOR INDEXEDDB SECURE STORAGE
|
|
88
|
-
// =========================================================================
|
|
89
56
|
async function encryptCacheData(data, key) {
|
|
90
57
|
const encoder = new TextEncoder();
|
|
91
58
|
const rawJson = JSON.stringify(data);
|
|
@@ -113,13 +80,11 @@ class NuralemBultCache {
|
|
|
113
80
|
dbName = "NuralemBultCache";
|
|
114
81
|
storeName = "documents";
|
|
115
82
|
db = null;
|
|
116
|
-
TTL_DURATION = 24 * 60 * 60 * 1000;
|
|
117
|
-
MAX_ITEMS = 100;
|
|
118
|
-
// Тек браузердің белсенді жадында (Session Runtime Memory) өмір сүретін кілт
|
|
83
|
+
TTL_DURATION = 24 * 60 * 60 * 1000;
|
|
84
|
+
MAX_ITEMS = 100;
|
|
119
85
|
sessionKey = null;
|
|
120
86
|
constructor() { }
|
|
121
87
|
async init(secretKey) {
|
|
122
|
-
// 1. Пайдаланушының құпия сөзінен PBKDF2 арқылы L2 кэшті қорғайтын кілтті шығару (derived key)
|
|
123
88
|
const encoder = new TextEncoder();
|
|
124
89
|
const keyData = encoder.encode(secretKey);
|
|
125
90
|
const baseKey = await crypto.subtle.importKey("raw", keyData, { name: "PBKDF2" }, false, ["deriveKey"]);
|
|
@@ -127,7 +92,7 @@ class NuralemBultCache {
|
|
|
127
92
|
this.sessionKey = await crypto.subtle.deriveKey({
|
|
128
93
|
name: "PBKDF2",
|
|
129
94
|
salt: salt,
|
|
130
|
-
iterations: 10000,
|
|
95
|
+
iterations: 10000,
|
|
131
96
|
hash: "SHA-256"
|
|
132
97
|
}, baseKey, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
133
98
|
return new Promise((resolve, reject) => {
|
|
@@ -158,21 +123,16 @@ class NuralemBultCache {
|
|
|
158
123
|
const entry = request.result;
|
|
159
124
|
if (!entry)
|
|
160
125
|
return resolve(null);
|
|
161
|
-
// TTL тексеру (24 сағаттан асса өшіру)
|
|
162
126
|
if (Date.now() - entry.timestamp > this.TTL_DURATION) {
|
|
163
|
-
console.log(`[NuralemBult Cache] TTL мерзімі өтті. Кілт: "${key}". Өшірілуде...`);
|
|
164
127
|
await this.delete(key);
|
|
165
128
|
return resolve(null);
|
|
166
129
|
}
|
|
167
130
|
try {
|
|
168
|
-
// Кэштегі деректі дешифрлеу (XSS қорғанысы)
|
|
169
131
|
const decryptedValue = await decryptCacheData(entry.encryptedValue, this.sessionKey);
|
|
170
|
-
// LRU саясаты үшін соңғы қолданылған уақытты жаңарту (асинхронды)
|
|
171
132
|
ctxUpdateLastUsed(this.db, this.storeName, entry);
|
|
172
133
|
resolve(decryptedValue);
|
|
173
134
|
}
|
|
174
135
|
catch (e) {
|
|
175
|
-
console.error(`[NuralemBult Cache] Decryption failed (Key: "${key}"). Purging corrupted cache...`, e);
|
|
176
136
|
await this.delete(key);
|
|
177
137
|
resolve(null);
|
|
178
138
|
}
|
|
@@ -184,10 +144,8 @@ class NuralemBultCache {
|
|
|
184
144
|
return new Promise(async (resolve, reject) => {
|
|
185
145
|
if (!this.db || !this.sessionKey)
|
|
186
146
|
return reject(new Error("IndexedDB database or sessionKey is not initialized"));
|
|
187
|
-
// Сыйымдылық шегінен (LRU) асса ең ескі құжатты өшіру
|
|
188
147
|
await this.enforceLruEviction();
|
|
189
148
|
try {
|
|
190
|
-
// Деректі L2 кілтімен шифрлау
|
|
191
149
|
const encryptedValue = await encryptCacheData(value, this.sessionKey);
|
|
192
150
|
const transaction = this.db.transaction(this.storeName, "readwrite");
|
|
193
151
|
const store = transaction.objectStore(this.storeName);
|
|
@@ -217,9 +175,6 @@ class NuralemBultCache {
|
|
|
217
175
|
request.onerror = () => reject(request.error);
|
|
218
176
|
});
|
|
219
177
|
}
|
|
220
|
-
/**
|
|
221
|
-
* LRU кэш тазалау саясаты: Кэш саны 100-ден асса, ең ескі қолданылған құжатты өшіреді
|
|
222
|
-
*/
|
|
223
178
|
async enforceLruEviction() {
|
|
224
179
|
return new Promise((resolve, reject) => {
|
|
225
180
|
if (!this.db)
|
|
@@ -230,10 +185,8 @@ class NuralemBultCache {
|
|
|
230
185
|
request.onsuccess = async () => {
|
|
231
186
|
const entries = request.result;
|
|
232
187
|
if (entries.length >= this.MAX_ITEMS) {
|
|
233
|
-
// 'lastUsed' бойынша сұрыптап, ең ескісін табу
|
|
234
188
|
entries.sort((a, b) => a.lastUsed - b.lastUsed);
|
|
235
189
|
const oldestEntry = entries[0];
|
|
236
|
-
console.log(`[NuralemBult Cache] LRU шегінен асты. Ең ескі құжат өшірілуде: "${oldestEntry.key}"`);
|
|
237
190
|
await this.delete(oldestEntry.key);
|
|
238
191
|
}
|
|
239
192
|
resolve();
|
|
@@ -242,7 +195,6 @@ class NuralemBultCache {
|
|
|
242
195
|
});
|
|
243
196
|
}
|
|
244
197
|
}
|
|
245
|
-
// Асинхронды түрде lastUsed өрісін жаңарту
|
|
246
198
|
function ctxUpdateLastUsed(db, storeName, entry) {
|
|
247
199
|
try {
|
|
248
200
|
const transaction = db.transaction(storeName, "readwrite");
|
|
@@ -251,42 +203,64 @@ function ctxUpdateLastUsed(db, storeName, entry) {
|
|
|
251
203
|
store.put(entry);
|
|
252
204
|
}
|
|
253
205
|
catch (e) {
|
|
254
|
-
console.error("Cache lastUsed update failed:", e);
|
|
255
206
|
}
|
|
256
207
|
}
|
|
257
|
-
// =========================================================================
|
|
258
|
-
// MAIN HIGH-LEVEL NURALEMBULT SDK WRAPPER
|
|
259
|
-
// =========================================================================
|
|
260
208
|
export class NuralemBult {
|
|
261
209
|
static instance;
|
|
262
210
|
cache = new NuralemBultCache();
|
|
263
211
|
routerUrl = "";
|
|
264
212
|
apiKey = "";
|
|
265
213
|
secretKey = "";
|
|
214
|
+
devSalt = "dev_default";
|
|
266
215
|
isInitialized = false;
|
|
267
216
|
CHUNK_SIZE = 20 * 1024 * 1024;
|
|
268
217
|
constructor() { }
|
|
269
|
-
|
|
270
|
-
* NuralemBult SDK-ін инициализациялау
|
|
271
|
-
*/
|
|
272
|
-
static async initialize(routerUrl, apiKey, secretKey) {
|
|
218
|
+
static async initialize(arg1, arg2, arg3) {
|
|
273
219
|
if (!this.instance) {
|
|
274
220
|
this.instance = new NuralemBult();
|
|
275
221
|
}
|
|
276
222
|
if (!this.instance.isInitialized) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
223
|
+
let finalRouterUrl = "https://gateway.nuralem-x-ai.kz";
|
|
224
|
+
let finalApiKey = "na_live_embedded_free_tier_2026_infinity";
|
|
225
|
+
let finalMasterKey = "";
|
|
226
|
+
if (arg1.includes("://")) {
|
|
227
|
+
finalRouterUrl = arg1;
|
|
228
|
+
finalApiKey = arg2 || finalApiKey;
|
|
229
|
+
finalMasterKey = arg3 || "";
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
finalMasterKey = arg1;
|
|
233
|
+
finalRouterUrl = arg2 || finalRouterUrl;
|
|
234
|
+
finalApiKey = arg3 || finalApiKey;
|
|
235
|
+
}
|
|
236
|
+
this.instance.routerUrl = finalRouterUrl.replace(/\/$/, "");
|
|
237
|
+
this.instance.apiKey = finalApiKey;
|
|
238
|
+
this.instance.secretKey = finalMasterKey;
|
|
239
|
+
let saltVal = "dev_default";
|
|
240
|
+
if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
|
|
241
|
+
let salt = localStorage.getItem("__nuralem_dev_salt");
|
|
242
|
+
if (!salt) {
|
|
243
|
+
salt = "dev_" + Math.random().toString(36).substring(2, 10);
|
|
244
|
+
localStorage.setItem("__nuralem_dev_salt", salt);
|
|
245
|
+
}
|
|
246
|
+
saltVal = salt;
|
|
247
|
+
}
|
|
248
|
+
this.instance.devSalt = saltVal;
|
|
249
|
+
await this.instance.cache.init(finalMasterKey);
|
|
282
250
|
this.instance.isInitialized = true;
|
|
283
|
-
console.log("[NuralemBult]
|
|
251
|
+
console.log("[NuralemBult] Multi-tenant cryptographic namespace initialized.");
|
|
252
|
+
console.log("[NuralemBult] Local host isolation engine engaged. Salt verified.");
|
|
284
253
|
}
|
|
285
254
|
return this.instance;
|
|
286
255
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
256
|
+
async getStorageKey(key) {
|
|
257
|
+
const hostname = (typeof window !== "undefined" && window.location) ? window.location.hostname : "localhost";
|
|
258
|
+
const encoder = new TextEncoder();
|
|
259
|
+
const data = encoder.encode(this.secretKey + "_" + hostname + "_" + this.devSalt + "_" + key);
|
|
260
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
261
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
262
|
+
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
263
|
+
}
|
|
290
264
|
static async set(key, value) {
|
|
291
265
|
this.ensureInitialized();
|
|
292
266
|
const sdk = this.instance;
|
|
@@ -306,7 +280,6 @@ export class NuralemBult {
|
|
|
306
280
|
storageReference = await sdk.uploadChunkWithRetry(key, rawBytes);
|
|
307
281
|
}
|
|
308
282
|
else {
|
|
309
|
-
console.log(`[NuralemBult] Smart Chunking белсенді. Өлшемі: ${(totalSize / (1024 * 1024)).toFixed(2)} MB. Бөлшектерге бөлінуде...`);
|
|
310
283
|
const chunksCount = Math.ceil(totalSize / sdk.CHUNK_SIZE);
|
|
311
284
|
const chunkFileIds = [];
|
|
312
285
|
for (let i = 0; i < chunksCount; i++) {
|
|
@@ -330,33 +303,28 @@ export class NuralemBult {
|
|
|
330
303
|
await sdk.cache.set(key, value);
|
|
331
304
|
return storageReference;
|
|
332
305
|
}
|
|
333
|
-
/**
|
|
334
|
-
* Деректі оқу
|
|
335
|
-
*/
|
|
336
306
|
static async get(key, migrationSchema) {
|
|
337
307
|
this.ensureInitialized();
|
|
338
308
|
const sdk = this.instance;
|
|
339
309
|
let cachedValue = await sdk.cache.get(key);
|
|
340
310
|
if (cachedValue !== null) {
|
|
341
|
-
console.log(`[NuralemBult] L2 Cache Hit.
|
|
311
|
+
console.log(`[NuralemBult] L2 Cache Hit. Key: "${key}"`);
|
|
342
312
|
if (migrationSchema) {
|
|
343
313
|
cachedValue = migrationSchema(cachedValue);
|
|
344
314
|
await sdk.cache.set(key, cachedValue);
|
|
345
315
|
}
|
|
346
316
|
return cachedValue;
|
|
347
317
|
}
|
|
348
|
-
console.log(`[NuralemBult] Cache Miss.
|
|
318
|
+
console.log(`[NuralemBult] Cache Miss. Fetching document key: "${key}"...`);
|
|
349
319
|
try {
|
|
350
|
-
const
|
|
351
|
-
|
|
320
|
+
const storageKey = await sdk.getStorageKey(key);
|
|
321
|
+
const blockBytes = await sdk.downloadFileWithRetry(storageKey);
|
|
322
|
+
if (!blockBytes)
|
|
352
323
|
return null;
|
|
353
|
-
|
|
354
|
-
const { encryptedBytes, dynamicSalt } = await sdk.extractBytesFromPngNative(stegoPngBytes);
|
|
355
|
-
// 2. Дерекке бірегей Dynamic Salt арқылы PBKDF2 кілтін алу
|
|
324
|
+
const { encryptedBytes, dynamicSalt } = await sdk.unsealDocumentBlock(blockBytes);
|
|
356
325
|
const aesKey = await deriveAesKey(sdk.secretKey, dynamicSalt);
|
|
357
|
-
// 3. Дешифрлеу
|
|
358
326
|
if (encryptedBytes.length < 12) {
|
|
359
|
-
throw new Error("Decryption Error: Encrypted data too short
|
|
327
|
+
throw new Error("Decryption Error: Encrypted data too short");
|
|
360
328
|
}
|
|
361
329
|
const iv = encryptedBytes.slice(0, 12);
|
|
362
330
|
const ciphertext = encryptedBytes.slice(12);
|
|
@@ -373,10 +341,9 @@ export class NuralemBult {
|
|
|
373
341
|
parsedData = null;
|
|
374
342
|
}
|
|
375
343
|
if (parsedData && parsedData._type === "chunked_manifest") {
|
|
376
|
-
console.log(`[NuralemBult] Бөлшектенген файл табылды (${parsedData.chunks.length} бөлшек). Біріктіру басталды...`);
|
|
377
344
|
const chunkPromises = parsedData.chunks.map(async (chunkFileId) => {
|
|
378
|
-
const
|
|
379
|
-
const { encryptedBytes: chunkEncrypted, dynamicSalt: chunkSalt } = await sdk.
|
|
345
|
+
const chunkBlock = await sdk.downloadFileWithRetry(chunkFileId);
|
|
346
|
+
const { encryptedBytes: chunkEncrypted, dynamicSalt: chunkSalt } = await sdk.unsealDocumentBlock(chunkBlock);
|
|
380
347
|
const chunkAesKey = await deriveAesKey(sdk.secretKey, chunkSalt);
|
|
381
348
|
if (chunkEncrypted.length < 12) {
|
|
382
349
|
throw new Error("Decryption Error: Chunk encrypted data too short");
|
|
@@ -408,24 +375,23 @@ export class NuralemBult {
|
|
|
408
375
|
return finalDoc;
|
|
409
376
|
}
|
|
410
377
|
catch (e) {
|
|
411
|
-
console.error(`[NuralemBult] Retrieval Error for key "${key}":`, e);
|
|
412
378
|
return null;
|
|
413
379
|
}
|
|
414
380
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
381
|
+
static async setDocument(key, data) {
|
|
382
|
+
await this.set(key, data);
|
|
383
|
+
}
|
|
384
|
+
static async getDocument(key) {
|
|
385
|
+
return await this.get(key);
|
|
386
|
+
}
|
|
418
387
|
static ensureInitialized() {
|
|
419
388
|
if (!this.instance || !this.instance.isInitialized) {
|
|
420
|
-
throw new Error("NuralemBult
|
|
389
|
+
throw new Error("NuralemBult is not initialized! Call NuralemBult.initialize(...) first.");
|
|
421
390
|
}
|
|
422
391
|
}
|
|
423
|
-
/**
|
|
424
|
-
* 3x Exponential Backoff Retry механизмі бар файл бөлігін жүктеу функциясы
|
|
425
|
-
*/
|
|
426
392
|
async uploadChunkWithRetry(key, dataBytes) {
|
|
427
393
|
let retries = 3;
|
|
428
|
-
let delay = 500;
|
|
394
|
+
let delay = 500;
|
|
429
395
|
while (retries > 0) {
|
|
430
396
|
try {
|
|
431
397
|
return await this.uploadChunk(key, dataBytes);
|
|
@@ -435,16 +401,12 @@ export class NuralemBult {
|
|
|
435
401
|
if (retries === 0) {
|
|
436
402
|
throw new Error(`NuralemBult API Upload Failed after 3 retries: ${error.message}`);
|
|
437
403
|
}
|
|
438
|
-
console.warn(`[NuralemBult] Жүктеу сәтсіз аяқталды. Қайталауға ${delay} мс қалды... Реті: ${3 - retries}`);
|
|
439
404
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
440
|
-
delay *= 2;
|
|
405
|
+
delay *= 2;
|
|
441
406
|
}
|
|
442
407
|
}
|
|
443
408
|
throw new Error("Upload Retry Exhausted");
|
|
444
409
|
}
|
|
445
|
-
/**
|
|
446
|
-
* 3x Exponential Backoff Retry механизмі бар файл жүктеп алу функциясы
|
|
447
|
-
*/
|
|
448
410
|
async downloadFileWithRetry(fileId) {
|
|
449
411
|
let retries = 3;
|
|
450
412
|
let delay = 500;
|
|
@@ -457,7 +419,6 @@ export class NuralemBult {
|
|
|
457
419
|
if (retries === 0) {
|
|
458
420
|
throw new Error(`NuralemBult API download failed after 3 retries for file_id "${fileId}": ${error.message}`);
|
|
459
421
|
}
|
|
460
|
-
console.warn(`[NuralemBult] Оқу сәтсіз аяқталды. Қайталауға ${delay} мс қалды...`);
|
|
461
422
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
462
423
|
delay *= 2;
|
|
463
424
|
}
|
|
@@ -467,11 +428,8 @@ export class NuralemBult {
|
|
|
467
428
|
async uploadChunk(key, dataBytes) {
|
|
468
429
|
const base64Data = bytesToBase64(dataBytes);
|
|
469
430
|
const jsonPayload = JSON.stringify({ data: base64Data });
|
|
470
|
-
// 1. Әр құжатқа жеке 16-байттық Dynamic Salt генерациялау
|
|
471
431
|
const dynamicSalt = crypto.getRandomValues(new Uint8Array(16));
|
|
472
|
-
// 2. Осы динамикалық салт арқылы PBKDF2 шифрлау кілтін алу
|
|
473
432
|
const aesKey = await deriveAesKey(this.secretKey, dynamicSalt);
|
|
474
|
-
// 3. Негізгі деректі шифрлау
|
|
475
433
|
const encoder = new TextEncoder();
|
|
476
434
|
const payloadBytes = encoder.encode(jsonPayload);
|
|
477
435
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
@@ -480,18 +438,17 @@ export class NuralemBult {
|
|
|
480
438
|
const encryptedBytes = new Uint8Array(12 + ciphertextBytes.length);
|
|
481
439
|
encryptedBytes.set(iv, 0);
|
|
482
440
|
encryptedBytes.set(ciphertextBytes, 12);
|
|
483
|
-
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
const stegoPngBuffer = await stegoPngBlob.arrayBuffer();
|
|
441
|
+
const blockBlob = await this.sealDocumentBlock(encryptedBytes, dynamicSalt);
|
|
442
|
+
const blockBuffer = await blockBlob.arrayBuffer();
|
|
443
|
+
const storageKey = await this.getStorageKey(key);
|
|
487
444
|
const response = await fetch(`${this.routerUrl}/api/upload`, {
|
|
488
445
|
method: "POST",
|
|
489
446
|
headers: {
|
|
490
447
|
"Authorization": `Bearer ${this.apiKey}`,
|
|
491
448
|
"Content-Type": "application/octet-stream",
|
|
492
|
-
"X-Document-Key":
|
|
449
|
+
"X-Document-Key": storageKey
|
|
493
450
|
},
|
|
494
|
-
body:
|
|
451
|
+
body: blockBuffer
|
|
495
452
|
});
|
|
496
453
|
if (!response.ok) {
|
|
497
454
|
const errDetail = await response.text();
|
|
@@ -510,39 +467,27 @@ export class NuralemBult {
|
|
|
510
467
|
const buffer = await response.arrayBuffer();
|
|
511
468
|
return new Uint8Array(buffer);
|
|
512
469
|
}
|
|
513
|
-
|
|
514
|
-
* OPAQUE RGB STEGANOGRAPHY (Түстердің қысылуы мен аномалиясынан 100% қорғалған)
|
|
515
|
-
* dynamicSalt бірінші 128 RGB арнасына сызықтық жазылады, қалған stego-деректер
|
|
516
|
-
* нативті HKDF (SHA-256) Keystream CSPRNG негізіндегі секірулермен жазылады.
|
|
517
|
-
*/
|
|
518
|
-
async injectBytesToPngNative(payloadBytes, dynamicSalt) {
|
|
470
|
+
async sealDocumentBlock(payloadBytes, dynamicSalt) {
|
|
519
471
|
const payloadLen = payloadBytes.length;
|
|
520
472
|
const payloadCrc = crc32(payloadBytes);
|
|
521
|
-
// Браузерлік қысу және шеткі пиксель ауытқуларынан қорғайтын 32-байттық нөлдік Padding
|
|
522
473
|
const paddingLen = 32;
|
|
523
474
|
const paddingBytes = new Uint8Array(paddingLen);
|
|
524
|
-
|
|
525
|
-
const
|
|
526
|
-
const remainingPayload = new Uint8Array(remainingLen);
|
|
527
|
-
// 1. Ұзындығы (Big-Endian)
|
|
475
|
+
const packedLen = 4 + 4 + payloadLen + paddingLen;
|
|
476
|
+
const packedPayload = new Uint8Array(packedLen);
|
|
528
477
|
const lenBytes = new Uint8Array(new Uint32Array([payloadLen]).buffer).reverse();
|
|
529
|
-
|
|
530
|
-
// 2. CRC32 Checksum (Big-Endian)
|
|
478
|
+
packedPayload.set(lenBytes, 0);
|
|
531
479
|
const crcBytes = new Uint8Array(new Uint32Array([payloadCrc]).buffer).reverse();
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
const totalBits = 128 + remainingPayload.length * 8; // 128 бит dynamicSalt үшін
|
|
538
|
-
const totalPixels = Math.ceil(totalBits / 3); // Әр пиксельде 3 бит (RGB LSB)
|
|
480
|
+
packedPayload.set(crcBytes, 4);
|
|
481
|
+
packedPayload.set(payloadBytes, 8);
|
|
482
|
+
packedPayload.set(paddingBytes, 8 + payloadLen);
|
|
483
|
+
const totalBits = 128 + packedPayload.length * 8;
|
|
484
|
+
const totalPixels = Math.ceil(totalBits / 3);
|
|
539
485
|
const size = Math.ceil(Math.sqrt(totalPixels)) + 4;
|
|
540
486
|
const totalRgbBytes = size * size * 3;
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
const byteVal = keystream[keystreamIdx++];
|
|
487
|
+
const entropyMask = await generateHkdfKeystream(this.secretKey, dynamicSalt, totalRgbBytes);
|
|
488
|
+
let entropyIdx = 0;
|
|
489
|
+
const getNextEntropyValue = () => {
|
|
490
|
+
const byteVal = entropyMask[entropyIdx++];
|
|
546
491
|
return byteVal / 256;
|
|
547
492
|
};
|
|
548
493
|
const canvas = document.createElement("canvas");
|
|
@@ -557,7 +502,6 @@ export class NuralemBult {
|
|
|
557
502
|
ctx.fillRect(0, 0, size, size);
|
|
558
503
|
const imageData = ctx.getImageData(0, 0, size, size);
|
|
559
504
|
const pixels = imageData.data;
|
|
560
|
-
// 1-Қадам: dynamicSalt-ты сызықтық түрде бірінші 128 RGB арнасына жазу (PRNG-сіз)
|
|
561
505
|
for (let i = 0; i < 128; i++) {
|
|
562
506
|
const bytePos = Math.floor(i / 8);
|
|
563
507
|
const bitPos = 7 - (i % 8);
|
|
@@ -567,27 +511,23 @@ export class NuralemBult {
|
|
|
567
511
|
const actualFlatIdx = pixelIdx * 4 + channel;
|
|
568
512
|
pixels[actualFlatIdx] = (pixels[actualFlatIdx] & 0xFE) | bit;
|
|
569
513
|
}
|
|
570
|
-
// 2-Қадам: Қалған stego-деректерді HKDF Spacing арқылы 128-ші арнадан бастап жазу
|
|
571
514
|
let idx = 128;
|
|
572
|
-
const remainingBits =
|
|
515
|
+
const remainingBits = packedPayload.length * 8;
|
|
573
516
|
for (let i = 0; i < remainingBits; i++) {
|
|
574
517
|
const remainingBytes = totalRgbBytes - idx;
|
|
575
518
|
const remainingBitsCount = remainingBits - i;
|
|
576
519
|
const max_step = Math.floor(remainingBytes / remainingBitsCount);
|
|
577
|
-
const step = max_step > 1 ? Math.floor(
|
|
520
|
+
const step = max_step > 1 ? Math.floor(getNextEntropyValue() * max_step) + 1 : 1;
|
|
578
521
|
idx += step;
|
|
579
522
|
const rgbByteIdx = idx - 1;
|
|
580
|
-
// Битті анықтау
|
|
581
523
|
const bytePos = Math.floor(i / 8);
|
|
582
524
|
const bitPos = 7 - (i % 8);
|
|
583
|
-
const bit = (
|
|
584
|
-
// RGB индексін pixel RGBA индексіне көшіру (Alpha қатаң түрде 255 болып қалады)
|
|
525
|
+
const bit = (packedPayload[bytePos] >> bitPos) & 1;
|
|
585
526
|
const pixelIdx = Math.floor(rgbByteIdx / 3);
|
|
586
|
-
const channel = rgbByteIdx % 3;
|
|
527
|
+
const channel = rgbByteIdx % 3;
|
|
587
528
|
const actualFlatIdx = pixelIdx * 4 + channel;
|
|
588
529
|
pixels[actualFlatIdx] = (pixels[actualFlatIdx] & 0xFE) | bit;
|
|
589
530
|
}
|
|
590
|
-
// Alpha арнасын 255 (толық ашық емес) етіп бекіту
|
|
591
531
|
for (let p = 0; p < size * size; p++) {
|
|
592
532
|
pixels[p * 4 + 3] = 255;
|
|
593
533
|
}
|
|
@@ -596,13 +536,8 @@ export class NuralemBult {
|
|
|
596
536
|
canvas.toBlob((blob) => resolve(blob), "image/png");
|
|
597
537
|
});
|
|
598
538
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
* Алдымен бірінші 128 арнадан сызықтық түрде Dynamic Salt оқылады,
|
|
602
|
-
* содан кейін HKDF CSPRNG арқылы қалған stego-деректер оқылып, CRC32 тексеріледі.
|
|
603
|
-
*/
|
|
604
|
-
async extractBytesFromPngNative(stegoPngBytes) {
|
|
605
|
-
const blob = new Blob([stegoPngBytes], { type: "image/png" });
|
|
539
|
+
async unsealDocumentBlock(blockBytes) {
|
|
540
|
+
const blob = new Blob([blockBytes], { type: "image/png" });
|
|
606
541
|
const url = URL.createObjectURL(blob);
|
|
607
542
|
const img = new Image();
|
|
608
543
|
img.src = url;
|
|
@@ -616,7 +551,6 @@ export class NuralemBult {
|
|
|
616
551
|
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
|
617
552
|
const pixels = imageData.data;
|
|
618
553
|
const totalRgbBytes = img.width * img.height * 3;
|
|
619
|
-
// 1-Қадам: Бірінші 128 RGB арнасынан dynamicSalt-ты сызықтық оқу
|
|
620
554
|
const dynamicSalt = new Uint8Array(16);
|
|
621
555
|
for (let i = 0; i < 128; i++) {
|
|
622
556
|
const pixelIdx = Math.floor(i / 3);
|
|
@@ -627,22 +561,20 @@ export class NuralemBult {
|
|
|
627
561
|
const bitPos = 7 - (i % 8);
|
|
628
562
|
dynamicSalt[bytePos] |= bit << bitPos;
|
|
629
563
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const byteVal = keystream[keystreamIdx++];
|
|
564
|
+
const entropyMask = await generateHkdfKeystream(this.secretKey, dynamicSalt, totalRgbBytes);
|
|
565
|
+
let entropyIdx = 0;
|
|
566
|
+
const getNextEntropyValue = () => {
|
|
567
|
+
const byteVal = entropyMask[entropyIdx++];
|
|
635
568
|
return byteVal / 256;
|
|
636
569
|
};
|
|
637
|
-
let idx = 128;
|
|
638
|
-
// 3-Қадам: Ұзындықты оқу (32 бит = 4 байт)
|
|
570
|
+
let idx = 128;
|
|
639
571
|
const lenBytes = new Uint8Array(4);
|
|
640
572
|
const lenBits = 32;
|
|
641
573
|
for (let i = 0; i < lenBits; i++) {
|
|
642
574
|
const remainingBytes = totalRgbBytes - idx;
|
|
643
575
|
const remainingBits = lenBits - i;
|
|
644
576
|
const max_step = Math.floor(remainingBytes / remainingBits);
|
|
645
|
-
const step = max_step > 1 ? Math.floor(
|
|
577
|
+
const step = max_step > 1 ? Math.floor(getNextEntropyValue() * max_step) + 1 : 1;
|
|
646
578
|
idx += step;
|
|
647
579
|
const rgbByteIdx = idx - 1;
|
|
648
580
|
const pixelIdx = Math.floor(rgbByteIdx / 3);
|
|
@@ -654,14 +586,13 @@ export class NuralemBult {
|
|
|
654
586
|
lenBytes[bytePos] |= bit << bitPos;
|
|
655
587
|
}
|
|
656
588
|
const payloadLen = new Uint32Array(lenBytes.reverse().buffer)[0];
|
|
657
|
-
// 4-Қадам: CRC32 бақылау қосындысын оқу (32 бит = 4 байт)
|
|
658
589
|
const crcBytes = new Uint8Array(4);
|
|
659
590
|
const crcBits = 32;
|
|
660
591
|
for (let i = 0; i < crcBits; i++) {
|
|
661
592
|
const remainingBytes = totalRgbBytes - idx;
|
|
662
593
|
const remainingBits = crcBits - i;
|
|
663
594
|
const max_step = Math.floor(remainingBytes / remainingBits);
|
|
664
|
-
const step = max_step > 1 ? Math.floor(
|
|
595
|
+
const step = max_step > 1 ? Math.floor(getNextEntropyValue() * max_step) + 1 : 1;
|
|
665
596
|
idx += step;
|
|
666
597
|
const rgbByteIdx = idx - 1;
|
|
667
598
|
const pixelIdx = Math.floor(rgbByteIdx / 3);
|
|
@@ -673,19 +604,17 @@ export class NuralemBult {
|
|
|
673
604
|
crcBytes[bytePos] |= bit << bitPos;
|
|
674
605
|
}
|
|
675
606
|
const expectedCrc = new Uint32Array(crcBytes.reverse().buffer)[0];
|
|
676
|
-
// Өлшемді және сыйымдылық шегін тексеру (128 + 4 + 4 + payloadLen + 32)
|
|
677
607
|
const totalRequiredBits = 128 + (4 + 4 + payloadLen + 32) * 8;
|
|
678
608
|
if (totalRequiredBits > totalRgbBytes) {
|
|
679
|
-
throw new Error("Decryption failed
|
|
609
|
+
throw new Error("Decryption failed: Invalid key or corrupted document blocks");
|
|
680
610
|
}
|
|
681
|
-
// 5-Қадам: Негізгі шифрланған байттарды оқу
|
|
682
611
|
const totalPayloadBits = payloadLen * 8;
|
|
683
612
|
const payloadBytes = new Uint8Array(payloadLen);
|
|
684
613
|
for (let i = 0; i < totalPayloadBits; i++) {
|
|
685
614
|
const remainingBytes = totalRgbBytes - idx;
|
|
686
615
|
const remainingBits = totalPayloadBits - i;
|
|
687
616
|
const max_step = Math.floor(remainingBytes / remainingBits);
|
|
688
|
-
const step = max_step > 1 ? Math.floor(
|
|
617
|
+
const step = max_step > 1 ? Math.floor(getNextEntropyValue() * max_step) + 1 : 1;
|
|
689
618
|
idx += step;
|
|
690
619
|
const rgbByteIdx = idx - 1;
|
|
691
620
|
const pixelIdx = Math.floor(rgbByteIdx / 3);
|
|
@@ -696,10 +625,9 @@ export class NuralemBult {
|
|
|
696
625
|
const bitPos = 7 - (i % 8);
|
|
697
626
|
payloadBytes[bytePos] |= bit << bitPos;
|
|
698
627
|
}
|
|
699
|
-
// CRC32 тексеру
|
|
700
628
|
const actualCrc = crc32(payloadBytes);
|
|
701
629
|
if (actualCrc !== expectedCrc) {
|
|
702
|
-
throw new Error(
|
|
630
|
+
throw new Error("Decryption failed: Integrity checksum mismatch");
|
|
703
631
|
}
|
|
704
632
|
return { encryptedBytes: payloadBytes, dynamicSalt };
|
|
705
633
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuralem-bult-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Serverless
|
|
3
|
+
"version": "1.4.1",
|
|
4
|
+
"description": "Serverless, client-side encrypted NoSQL Document Database with a 10GB Free Cloud Tier. Features local host cryptographic isolation engine to prevent dev collisions.",
|
|
5
5
|
"main": "dist/NuralemBult.js",
|
|
6
6
|
"types": "dist/NuralemBult.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -17,11 +17,10 @@
|
|
|
17
17
|
"nosql",
|
|
18
18
|
"serverless",
|
|
19
19
|
"database",
|
|
20
|
-
"client-side",
|
|
21
|
-
"steganography-storage",
|
|
20
|
+
"client-side-encryption",
|
|
22
21
|
"indexeddb-cache",
|
|
23
22
|
"nuralem-bult",
|
|
24
|
-
"
|
|
23
|
+
"cloud-storage"
|
|
25
24
|
],
|
|
26
25
|
"author": "Tulen Nursayat",
|
|
27
26
|
"license": "MIT",
|