@storacha/encrypt-upload-client 1.1.56 → 1.1.58
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/dist/config/constants.d.ts +3 -3
- package/dist/config/constants.js +4 -3
- package/dist/config/env.d.ts +9 -6
- package/dist/config/service.d.ts +13 -13
- package/dist/core/client.d.ts +54 -41
- package/dist/core/client.js +68 -56
- package/dist/core/errors.d.ts +6 -6
- package/dist/core/metadata/encrypted-metadata.d.ts +13 -8
- package/dist/core/metadata/kms-metadata.d.ts +68 -36
- package/dist/core/metadata/lit-metadata.d.ts +63 -28
- package/dist/crypto/adapters/kms-crypto-adapter.d.ts +172 -137
- package/dist/crypto/adapters/lit-crypto-adapter.d.ts +107 -86
- package/dist/crypto/factories.browser.d.ts +9 -5
- package/dist/crypto/factories.browser.js +15 -7
- package/dist/crypto/factories.node.d.ts +13 -6
- package/dist/crypto/factories.node.js +19 -13
- package/dist/crypto/index.d.ts +5 -5
- package/dist/crypto/index.js +5 -5
- package/dist/crypto/symmetric/generic-aes-ctr-streaming-crypto.d.ts +58 -54
- package/dist/crypto/symmetric/generic-aes-ctr-streaming-crypto.js +174 -146
- package/dist/crypto/symmetric/node-aes-cbc-crypto.d.ts +36 -32
- package/dist/crypto/symmetric/node-aes-cbc-crypto.js +101 -95
- package/dist/examples/decrypt-test.d.ts +2 -2
- package/dist/examples/decrypt-test.js +78 -69
- package/dist/examples/encrypt-test.d.ts +5 -3
- package/dist/examples/encrypt-test.js +58 -55
- package/dist/handlers/decrypt-handler.d.ts +19 -5
- package/dist/handlers/encrypt-handler.d.ts +9 -3
- package/dist/handlers/encrypt-handler.js +93 -57
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/protocols/lit.d.ts +33 -9
- package/dist/protocols/lit.js +134 -98
- package/dist/test/cid-verification.spec.d.ts +2 -2
- package/dist/test/cid-verification.spec.js +341 -313
- package/dist/test/crypto-compatibility.spec.d.ts +2 -2
- package/dist/test/crypto-compatibility.spec.js +184 -120
- package/dist/test/crypto-counter-security.spec.d.ts +2 -2
- package/dist/test/crypto-counter-security.spec.js +177 -138
- package/dist/test/crypto-streaming.spec.d.ts +2 -2
- package/dist/test/crypto-streaming.spec.js +208 -126
- package/dist/test/encrypted-metadata.spec.d.ts +2 -2
- package/dist/test/encrypted-metadata.spec.js +89 -62
- package/dist/test/factories.spec.d.ts +2 -2
- package/dist/test/factories.spec.js +275 -139
- package/dist/test/file-metadata.spec.d.ts +2 -2
- package/dist/test/file-metadata.spec.js +472 -416
- package/dist/test/fixtures/test-fixtures.d.ts +25 -20
- package/dist/test/fixtures/test-fixtures.js +61 -53
- package/dist/test/helpers/test-file-utils.d.ts +19 -14
- package/dist/test/helpers/test-file-utils.js +78 -76
- package/dist/test/https-enforcement.spec.d.ts +2 -2
- package/dist/test/https-enforcement.spec.js +278 -124
- package/dist/test/kms-crypto-adapter.spec.d.ts +2 -2
- package/dist/test/kms-crypto-adapter.spec.js +473 -304
- package/dist/test/lit-crypto-adapter.spec.d.ts +2 -2
- package/dist/test/lit-crypto-adapter.spec.js +206 -118
- package/dist/test/memory-efficiency.spec.d.ts +2 -2
- package/dist/test/memory-efficiency.spec.js +100 -87
- package/dist/test/mocks/key-manager.d.ts +71 -38
- package/dist/test/mocks/key-manager.js +129 -113
- package/dist/test/node-crypto-adapter.spec.d.ts +2 -2
- package/dist/test/node-crypto-adapter.spec.js +155 -102
- package/dist/test/node-generic-crypto-adapter.spec.d.ts +2 -2
- package/dist/test/node-generic-crypto-adapter.spec.js +134 -94
- package/dist/test/setup.d.ts +2 -2
- package/dist/test/setup.js +8 -9
- package/dist/tsconfig.spec.tsbuildinfo +1 -1
- package/dist/types.d.ts +219 -181
- package/dist/utils/file-metadata.d.ts +19 -13
- package/dist/utils.d.ts +14 -5
- package/package.json +4 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import './setup.js'
|
|
2
|
-
import { test, describe } from 'node:test'
|
|
3
|
-
import assert from 'node:assert'
|
|
4
|
-
import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js'
|
|
1
|
+
import './setup.js'
|
|
2
|
+
import { test, describe } from 'node:test'
|
|
3
|
+
import assert from 'node:assert'
|
|
4
|
+
import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-aes-ctr-streaming-crypto.js'
|
|
5
5
|
/**
|
|
6
6
|
* Security tests for AES-CTR counter management
|
|
7
7
|
*
|
|
@@ -9,139 +9,178 @@ import { GenericAesCtrStreamingCrypto } from '../src/crypto/symmetric/generic-ae
|
|
|
9
9
|
* which is critical for AES-CTR security.
|
|
10
10
|
*/
|
|
11
11
|
await describe('AES-CTR Counter Security', async () => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
12
|
+
await test('should increment counter by blocks, not chunks', async () => {
|
|
13
|
+
const crypto = new GenericAesCtrStreamingCrypto()
|
|
14
|
+
// Test the incrementCounter function directly
|
|
15
|
+
const baseCounter = new Uint8Array(16).fill(0)
|
|
16
|
+
// Test counter increments for block counts
|
|
17
|
+
const counter1 = crypto.incrementCounter(baseCounter, 0) // First block
|
|
18
|
+
const counter2 = crypto.incrementCounter(baseCounter, 1) // Second block
|
|
19
|
+
const counter3 = crypto.incrementCounter(baseCounter, 2) // Third block
|
|
20
|
+
const counter4 = crypto.incrementCounter(baseCounter, 7) // Eighth block
|
|
21
|
+
// Verify each counter is unique
|
|
22
|
+
assert.notDeepEqual(
|
|
23
|
+
counter1,
|
|
24
|
+
counter2,
|
|
25
|
+
'Block 1 and 2 should have different counters'
|
|
26
|
+
)
|
|
27
|
+
assert.notDeepEqual(
|
|
28
|
+
counter2,
|
|
29
|
+
counter3,
|
|
30
|
+
'Block 2 and 3 should have different counters'
|
|
31
|
+
)
|
|
32
|
+
assert.notDeepEqual(
|
|
33
|
+
counter3,
|
|
34
|
+
counter4,
|
|
35
|
+
'Block 3 and 8 should have different counters'
|
|
36
|
+
)
|
|
37
|
+
// Verify counter progression is correct
|
|
38
|
+
assert.strictEqual(counter1[15], 0, 'First counter should be 0')
|
|
39
|
+
assert.strictEqual(counter2[15], 1, 'Second counter should be 1')
|
|
40
|
+
assert.strictEqual(counter3[15], 2, 'Third counter should be 2')
|
|
41
|
+
assert.strictEqual(counter4[15], 7, 'Eighth counter should be 7')
|
|
42
|
+
console.log('Counter increments by blocks correctly')
|
|
43
|
+
})
|
|
44
|
+
await test('should handle chunk sizes correctly', async () => {
|
|
45
|
+
const crypto = new GenericAesCtrStreamingCrypto()
|
|
46
|
+
// Test different chunk sizes and verify block calculations
|
|
47
|
+
const testData = new Uint8Array(100).fill(0xaa) // 7 blocks (100 bytes = ceil(100/16) = 7)
|
|
48
|
+
const blob = new Blob([testData])
|
|
49
|
+
const { key, iv, encryptedStream } = await crypto.encryptStream(blob)
|
|
50
|
+
// Read encrypted data
|
|
51
|
+
const reader = encryptedStream.getReader()
|
|
52
|
+
let encryptedChunks = []
|
|
53
|
+
let done = false
|
|
54
|
+
while (!done) {
|
|
55
|
+
const result = await reader.read()
|
|
56
|
+
done = result.done
|
|
57
|
+
if (result.value) {
|
|
58
|
+
encryptedChunks.push(result.value)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Verify we got data
|
|
62
|
+
assert(encryptedChunks.length > 0, 'Should have encrypted chunks')
|
|
63
|
+
// Decrypt to verify correctness
|
|
64
|
+
const combinedEncrypted = new Uint8Array(
|
|
65
|
+
encryptedChunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
|
66
|
+
)
|
|
67
|
+
let offset = 0
|
|
68
|
+
for (const chunk of encryptedChunks) {
|
|
69
|
+
combinedEncrypted.set(chunk, offset)
|
|
70
|
+
offset += chunk.length
|
|
71
|
+
}
|
|
72
|
+
const encryptedStream2 = new ReadableStream({
|
|
73
|
+
start(controller) {
|
|
74
|
+
controller.enqueue(combinedEncrypted)
|
|
75
|
+
controller.close()
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
const decryptedStream = await crypto.decryptStream(
|
|
79
|
+
encryptedStream2,
|
|
80
|
+
key,
|
|
81
|
+
iv
|
|
82
|
+
)
|
|
83
|
+
const decryptedReader = decryptedStream.getReader()
|
|
84
|
+
let decryptedChunks = []
|
|
85
|
+
done = false
|
|
86
|
+
while (!done) {
|
|
87
|
+
const result = await decryptedReader.read()
|
|
88
|
+
done = result.done
|
|
89
|
+
if (result.value) {
|
|
90
|
+
decryptedChunks.push(result.value)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Combine decrypted chunks
|
|
94
|
+
const combinedDecrypted = new Uint8Array(
|
|
95
|
+
decryptedChunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
|
96
|
+
)
|
|
97
|
+
offset = 0
|
|
98
|
+
for (const chunk of decryptedChunks) {
|
|
99
|
+
combinedDecrypted.set(chunk, offset)
|
|
100
|
+
offset += chunk.length
|
|
101
|
+
}
|
|
102
|
+
// Verify perfect round-trip
|
|
103
|
+
assert.deepStrictEqual(
|
|
104
|
+
combinedDecrypted,
|
|
105
|
+
testData,
|
|
106
|
+
'Decrypt must produce exact original data'
|
|
107
|
+
)
|
|
108
|
+
console.log('Chunk handling with block-based counters works correctly')
|
|
109
|
+
})
|
|
110
|
+
await test('should prevent keystream reuse in different chunk sizes', async () => {
|
|
111
|
+
const crypto = new GenericAesCtrStreamingCrypto()
|
|
112
|
+
// Test with different chunk sizes that would have caused reuse with old implementation
|
|
113
|
+
const testSizes = [15, 16, 17, 32, 33, 64, 65]
|
|
114
|
+
for (const size of testSizes) {
|
|
115
|
+
const testData = new Uint8Array(size).fill(0xbb)
|
|
116
|
+
const blob = new Blob([testData])
|
|
117
|
+
const { key, iv, encryptedStream } = await crypto.encryptStream(blob)
|
|
118
|
+
// Read encrypted data
|
|
119
|
+
const reader = encryptedStream.getReader()
|
|
120
|
+
let encryptedData = new Uint8Array(0)
|
|
121
|
+
let done = false
|
|
122
|
+
while (!done) {
|
|
123
|
+
const result = await reader.read()
|
|
124
|
+
done = result.done
|
|
125
|
+
if (result.value) {
|
|
126
|
+
const combined = new Uint8Array(
|
|
127
|
+
encryptedData.length + result.value.length
|
|
128
|
+
)
|
|
129
|
+
combined.set(encryptedData)
|
|
130
|
+
combined.set(result.value, encryptedData.length)
|
|
131
|
+
encryptedData = combined
|
|
48
132
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
133
|
+
}
|
|
134
|
+
// Decrypt and verify
|
|
135
|
+
const encryptedStream2 = new ReadableStream({
|
|
136
|
+
start(controller) {
|
|
137
|
+
controller.enqueue(encryptedData)
|
|
138
|
+
controller.close()
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
const decryptedStream = await crypto.decryptStream(
|
|
142
|
+
encryptedStream2,
|
|
143
|
+
key,
|
|
144
|
+
iv
|
|
145
|
+
)
|
|
146
|
+
const decryptedReader = decryptedStream.getReader()
|
|
147
|
+
let decryptedData = new Uint8Array(0)
|
|
148
|
+
done = false
|
|
149
|
+
while (!done) {
|
|
150
|
+
const result = await decryptedReader.read()
|
|
151
|
+
done = result.done
|
|
152
|
+
if (result.value) {
|
|
153
|
+
const combined = new Uint8Array(
|
|
154
|
+
decryptedData.length + result.value.length
|
|
155
|
+
)
|
|
156
|
+
combined.set(decryptedData)
|
|
157
|
+
combined.set(result.value, decryptedData.length)
|
|
158
|
+
decryptedData = combined
|
|
57
159
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
});
|
|
86
|
-
await test('should prevent keystream reuse in different chunk sizes', async () => {
|
|
87
|
-
const crypto = new GenericAesCtrStreamingCrypto();
|
|
88
|
-
// Test with different chunk sizes that would have caused reuse with old implementation
|
|
89
|
-
const testSizes = [15, 16, 17, 32, 33, 64, 65];
|
|
90
|
-
for (const size of testSizes) {
|
|
91
|
-
const testData = new Uint8Array(size).fill(0xbb);
|
|
92
|
-
const blob = new Blob([testData]);
|
|
93
|
-
const { key, iv, encryptedStream } = await crypto.encryptStream(blob);
|
|
94
|
-
// Read encrypted data
|
|
95
|
-
const reader = encryptedStream.getReader();
|
|
96
|
-
let encryptedData = new Uint8Array(0);
|
|
97
|
-
let done = false;
|
|
98
|
-
while (!done) {
|
|
99
|
-
const result = await reader.read();
|
|
100
|
-
done = result.done;
|
|
101
|
-
if (result.value) {
|
|
102
|
-
const combined = new Uint8Array(encryptedData.length + result.value.length);
|
|
103
|
-
combined.set(encryptedData);
|
|
104
|
-
combined.set(result.value, encryptedData.length);
|
|
105
|
-
encryptedData = combined;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// Decrypt and verify
|
|
109
|
-
const encryptedStream2 = new ReadableStream({
|
|
110
|
-
start(controller) {
|
|
111
|
-
controller.enqueue(encryptedData);
|
|
112
|
-
controller.close();
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
const decryptedStream = await crypto.decryptStream(encryptedStream2, key, iv);
|
|
116
|
-
const decryptedReader = decryptedStream.getReader();
|
|
117
|
-
let decryptedData = new Uint8Array(0);
|
|
118
|
-
done = false;
|
|
119
|
-
while (!done) {
|
|
120
|
-
const result = await decryptedReader.read();
|
|
121
|
-
done = result.done;
|
|
122
|
-
if (result.value) {
|
|
123
|
-
const combined = new Uint8Array(decryptedData.length + result.value.length);
|
|
124
|
-
combined.set(decryptedData);
|
|
125
|
-
combined.set(result.value, decryptedData.length);
|
|
126
|
-
decryptedData = combined;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
assert.deepStrictEqual(decryptedData, testData, `Encryption/decryption failed for ${size}-byte chunk`);
|
|
130
|
-
}
|
|
131
|
-
console.log('No keystream reuse detected across different chunk sizes');
|
|
132
|
-
});
|
|
133
|
-
await test('should throw a clear error if Web Crypto API is not available', async () => {
|
|
134
|
-
// Save and remove globalThis.crypto
|
|
135
|
-
const originalCrypto = globalThis.crypto;
|
|
136
|
-
try {
|
|
137
|
-
// @ts-expect-error
|
|
138
|
-
delete globalThis.crypto;
|
|
139
|
-
assert.throws(() => new GenericAesCtrStreamingCrypto(), /Web Crypto API|crypto( is)? not available/i, 'Should throw if Web Crypto API is missing');
|
|
140
|
-
}
|
|
141
|
-
finally {
|
|
142
|
-
// Restore globalThis.crypto
|
|
143
|
-
globalThis.crypto = originalCrypto;
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
//# sourceMappingURL=crypto-counter-security.spec.js.map
|
|
160
|
+
}
|
|
161
|
+
assert.deepStrictEqual(
|
|
162
|
+
decryptedData,
|
|
163
|
+
testData,
|
|
164
|
+
`Encryption/decryption failed for ${size}-byte chunk`
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
console.log('No keystream reuse detected across different chunk sizes')
|
|
168
|
+
})
|
|
169
|
+
await test('should throw a clear error if Web Crypto API is not available', async () => {
|
|
170
|
+
// Save and remove globalThis.crypto
|
|
171
|
+
const originalCrypto = globalThis.crypto
|
|
172
|
+
try {
|
|
173
|
+
// @ts-expect-error
|
|
174
|
+
delete globalThis.crypto
|
|
175
|
+
assert.throws(
|
|
176
|
+
() => new GenericAesCtrStreamingCrypto(),
|
|
177
|
+
/Web Crypto API|crypto( is)? not available/i,
|
|
178
|
+
'Should throw if Web Crypto API is missing'
|
|
179
|
+
)
|
|
180
|
+
} finally {
|
|
181
|
+
// Restore globalThis.crypto
|
|
182
|
+
globalThis.crypto = originalCrypto
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
//# sourceMappingURL=crypto-counter-security.spec.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {}
|
|
2
|
-
//# sourceMappingURL=crypto-streaming.spec.d.ts.map
|
|
1
|
+
export {}
|
|
2
|
+
//# sourceMappingURL=crypto-streaming.spec.d.ts.map
|