@storacha/encrypt-upload-client 0.0.36 → 1.0.0-0
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/core/client.d.ts +8 -12
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +12 -21
- package/dist/core/metadata/encrypted-metadata.d.ts +8 -0
- package/dist/core/metadata/encrypted-metadata.d.ts.map +1 -0
- package/dist/core/metadata/encrypted-metadata.js +69 -0
- package/dist/core/metadata/kms-metadata.d.ts +36 -0
- package/dist/core/metadata/kms-metadata.d.ts.map +1 -0
- package/dist/core/metadata/kms-metadata.js +156 -0
- package/dist/core/{encrypted-metadata.d.ts → metadata/lit-metadata.d.ts} +11 -11
- package/dist/core/metadata/lit-metadata.d.ts.map +1 -0
- package/dist/core/{encrypted-metadata.js → metadata/lit-metadata.js} +32 -42
- package/dist/crypto/adapters/kms-crypto-adapter.d.ts +148 -0
- package/dist/crypto/adapters/kms-crypto-adapter.d.ts.map +1 -0
- package/dist/crypto/adapters/kms-crypto-adapter.js +321 -0
- package/dist/crypto/adapters/lit-crypto-adapter.d.ts +96 -0
- package/dist/crypto/adapters/lit-crypto-adapter.d.ts.map +1 -0
- package/dist/crypto/adapters/lit-crypto-adapter.js +210 -0
- package/dist/crypto/factories.browser.d.ts +20 -0
- package/dist/crypto/factories.browser.d.ts.map +1 -0
- package/dist/crypto/factories.browser.js +28 -0
- package/dist/crypto/factories.node.d.ts +26 -0
- package/dist/crypto/factories.node.d.ts.map +1 -0
- package/dist/crypto/factories.node.js +38 -0
- package/dist/crypto/index.d.ts +5 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +7 -0
- package/dist/crypto/symmetric/generic-aes-ctr-streaming-crypto.d.ts +76 -0
- package/dist/crypto/symmetric/generic-aes-ctr-streaming-crypto.d.ts.map +1 -0
- package/dist/crypto/symmetric/generic-aes-ctr-streaming-crypto.js +177 -0
- package/dist/crypto/symmetric/node-aes-cbc-crypto.d.ts +43 -0
- package/dist/crypto/symmetric/node-aes-cbc-crypto.d.ts.map +1 -0
- package/dist/crypto/symmetric/node-aes-cbc-crypto.js +110 -0
- package/dist/handlers/decrypt-handler.d.ts +9 -4
- package/dist/handlers/decrypt-handler.d.ts.map +1 -1
- package/dist/handlers/decrypt-handler.js +62 -93
- package/dist/handlers/encrypt-handler.d.ts +1 -1
- package/dist/handlers/encrypt-handler.d.ts.map +1 -1
- package/dist/handlers/encrypt-handler.js +31 -41
- package/dist/protocols/lit.d.ts +1 -3
- package/dist/protocols/lit.d.ts.map +1 -1
- package/dist/types.d.ts +135 -20
- package/dist/types.d.ts.map +1 -1
- package/package.json +27 -18
- package/dist/core/encrypted-metadata.d.ts.map +0 -1
- package/dist/crypto-adapters/browser-crypto-adapter.d.ts +0 -42
- package/dist/crypto-adapters/browser-crypto-adapter.d.ts.map +0 -1
- package/dist/crypto-adapters/browser-crypto-adapter.js +0 -109
- package/dist/crypto-adapters/node-crypto-adapter.d.ts +0 -17
- package/dist/crypto-adapters/node-crypto-adapter.d.ts.map +0 -1
- package/dist/crypto-adapters/node-crypto-adapter.js +0 -66
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KMSCryptoAdapter implements the complete CryptoAdapter interface using KMS.
|
|
3
|
+
* It uses composition with a SymmetricCrypto implementation for file encryption/decryption
|
|
4
|
+
* and KMS via private gateway for key management operations.
|
|
5
|
+
*
|
|
6
|
+
* @class
|
|
7
|
+
* @implements {Type.CryptoAdapter}
|
|
8
|
+
*/
|
|
9
|
+
export class KMSCryptoAdapter implements Type.CryptoAdapter {
|
|
10
|
+
/**
|
|
11
|
+
* Create a new KMS crypto adapter
|
|
12
|
+
*
|
|
13
|
+
* @param {Type.SymmetricCrypto} symmetricCrypto - The symmetric crypto implementation (browser or node)
|
|
14
|
+
* @param {URL|string} keyManagerServiceURL - The key manager service URL
|
|
15
|
+
* @param {`did:${string}:${string}`} keyManagerServiceDID - The key manager service DID
|
|
16
|
+
* @param {object} [options] - Optional configuration
|
|
17
|
+
* @param {boolean} [options.allowInsecureHttp] - Allow HTTP for testing (NOT for production)
|
|
18
|
+
*/
|
|
19
|
+
constructor(symmetricCrypto: Type.SymmetricCrypto, keyManagerServiceURL: URL | string, keyManagerServiceDID: `did:${string}:${string}`, options?: {
|
|
20
|
+
allowInsecureHttp?: boolean | undefined;
|
|
21
|
+
});
|
|
22
|
+
symmetricCrypto: Type.SymmetricCrypto;
|
|
23
|
+
keyManagerServiceURL: URL;
|
|
24
|
+
keyManagerServiceDID: import("@ucanto/client").PrincipalView<`did:${string}:${string}`>;
|
|
25
|
+
/**
|
|
26
|
+
* Encrypt a stream of data using the symmetric crypto
|
|
27
|
+
*
|
|
28
|
+
* @param {Type.BlobLike} data
|
|
29
|
+
*/
|
|
30
|
+
encryptStream(data: Type.BlobLike): Promise<Type.EncryptOutput>;
|
|
31
|
+
/**
|
|
32
|
+
* Decrypt a stream of data using the symmetric crypto
|
|
33
|
+
*
|
|
34
|
+
* @param {ReadableStream} encryptedData
|
|
35
|
+
* @param {Uint8Array} key
|
|
36
|
+
* @param {Uint8Array} iv
|
|
37
|
+
*/
|
|
38
|
+
decryptStream(encryptedData: ReadableStream, key: Uint8Array, iv: Uint8Array): Promise<ReadableStream<any>>;
|
|
39
|
+
/**
|
|
40
|
+
* Encrypt a symmetric key using the KMS
|
|
41
|
+
*
|
|
42
|
+
* @param {Uint8Array} key
|
|
43
|
+
* @param {Uint8Array} iv
|
|
44
|
+
* @param {Type.EncryptionConfig} encryptionConfig
|
|
45
|
+
* @returns {Promise<Type.EncryptedKeyResult>}
|
|
46
|
+
*/
|
|
47
|
+
encryptSymmetricKey(key: Uint8Array, iv: Uint8Array, encryptionConfig: Type.EncryptionConfig): Promise<Type.EncryptedKeyResult>;
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} encryptedKey
|
|
50
|
+
* @param {object} configs
|
|
51
|
+
* @param {Type.DecryptionOptions} configs.decryptionOptions
|
|
52
|
+
* @param {Type.ExtractedMetadata} configs.metadata
|
|
53
|
+
* @param {Uint8Array} configs.delegationCAR
|
|
54
|
+
* @param {Type.AnyLink} configs.resourceCID
|
|
55
|
+
* @param {import('@storacha/client/types').Signer<import('@storacha/client/types').DID, import('@storacha/client/types').SigAlg>} configs.issuer
|
|
56
|
+
* @param {import('@storacha/client/types').DID} configs.audience
|
|
57
|
+
*/
|
|
58
|
+
decryptSymmetricKey(encryptedKey: string, configs: {
|
|
59
|
+
decryptionOptions: Type.DecryptionOptions;
|
|
60
|
+
metadata: Type.ExtractedMetadata;
|
|
61
|
+
delegationCAR: Uint8Array;
|
|
62
|
+
resourceCID: Type.AnyLink;
|
|
63
|
+
issuer: import("@storacha/client/types").Signer<import("@storacha/client/types").DID, import("@storacha/client/types").SigAlg>;
|
|
64
|
+
audience: import("@storacha/client/types").DID;
|
|
65
|
+
}): Promise<{
|
|
66
|
+
key: Uint8Array;
|
|
67
|
+
iv: Uint8Array;
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* Get decrypted symmetric key in base64 string from KMS via private gateway
|
|
71
|
+
*
|
|
72
|
+
* @param {string} encryptedSymmetricKey - The encrypted symmetric key (base64-encoded)
|
|
73
|
+
* @param {Type.SpaceDID} spaceDID - The space DID
|
|
74
|
+
* @param {import('@ucanto/interface').Proof} delegationProof - The delegation proof
|
|
75
|
+
* @param {import('@storacha/client/types').Signer<import('@storacha/client/types').DID, import('@storacha/client/types').SigAlg>} issuer - The issuer
|
|
76
|
+
* @returns {Promise<{decryptedSymmetricKey: string}>} - The decrypted symmetric key (base64-encoded)
|
|
77
|
+
*/
|
|
78
|
+
getDecryptedSymmetricKey(encryptedSymmetricKey: string, spaceDID: Type.SpaceDID, delegationProof: import("@ucanto/interface").Proof, issuer: import("@storacha/client/types").Signer<import("@storacha/client/types").DID, import("@storacha/client/types").SigAlg>): Promise<{
|
|
79
|
+
decryptedSymmetricKey: string;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Extract the encrypted metadata from the CAR file
|
|
83
|
+
* KMS adapter only handles KMS format (encrypted-metadata@0.2)
|
|
84
|
+
*
|
|
85
|
+
* @param {Uint8Array} car
|
|
86
|
+
* @returns {Type.ExtractedMetadata}
|
|
87
|
+
*/
|
|
88
|
+
extractEncryptedMetadata(car: Uint8Array): Type.ExtractedMetadata;
|
|
89
|
+
/**
|
|
90
|
+
* @param {Type.ExtractedMetadata} metadata
|
|
91
|
+
* @returns {string}
|
|
92
|
+
*/
|
|
93
|
+
getEncryptedKey(metadata: Type.ExtractedMetadata): string;
|
|
94
|
+
/**
|
|
95
|
+
* Encode metadata for upload
|
|
96
|
+
*
|
|
97
|
+
* @param {string} encryptedDataCID - The CID of the encrypted data
|
|
98
|
+
* @param {string} encryptedKey - The encrypted key
|
|
99
|
+
* @param {Type.KMSKeyMetadata} metadata - The metadata to encode
|
|
100
|
+
* @returns {Promise<{ cid: import('@storacha/upload-client/types').AnyLink, bytes: Uint8Array }>} - The encoded metadata
|
|
101
|
+
*/
|
|
102
|
+
encodeMetadata(encryptedDataCID: string, encryptedKey: string, metadata: Type.KMSKeyMetadata): Promise<{
|
|
103
|
+
cid: import("@storacha/upload-client/types").AnyLink;
|
|
104
|
+
bytes: Uint8Array;
|
|
105
|
+
}>;
|
|
106
|
+
/**
|
|
107
|
+
* Get the RSA public key from the space/encryption/setup
|
|
108
|
+
*
|
|
109
|
+
* @param {Type.EncryptionConfig} encryptionConfig
|
|
110
|
+
* @returns {Promise<{ publicKey: string, provider: string, algorithm: string }>}
|
|
111
|
+
*/
|
|
112
|
+
getSpacePublicKey(encryptionConfig: Type.EncryptionConfig): Promise<{
|
|
113
|
+
publicKey: string;
|
|
114
|
+
provider: string;
|
|
115
|
+
algorithm: string;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* Get the Web Crypto API SubtleCrypto interface (universal compatibility)
|
|
119
|
+
*
|
|
120
|
+
* @returns {SubtleCrypto} - The SubtleCrypto interface
|
|
121
|
+
*/
|
|
122
|
+
getSubtleCrypto(): SubtleCrypto;
|
|
123
|
+
/**
|
|
124
|
+
* Encrypt data with RSA-OAEP using the public key
|
|
125
|
+
*
|
|
126
|
+
* @param {Uint8Array} dataToEncrypt
|
|
127
|
+
* @param {string} publicKeyPem
|
|
128
|
+
* @returns {Promise<Uint8Array>}
|
|
129
|
+
*/
|
|
130
|
+
encryptWithRSA(dataToEncrypt: Uint8Array, publicKeyPem: string): Promise<Uint8Array>;
|
|
131
|
+
/**
|
|
132
|
+
* Convert PEM-encoded public key to ArrayBuffer for Web Crypto API
|
|
133
|
+
*
|
|
134
|
+
* @param {string} pem - PEM-encoded public key string
|
|
135
|
+
* @returns {ArrayBuffer} - DER-encoded key data for crypto.subtle.importKey()
|
|
136
|
+
*/
|
|
137
|
+
pemToArrayBuffer(pem: string): ArrayBuffer;
|
|
138
|
+
newKeyManagerServiceConnection(): import("@ucanto/interface").ConnectionView<any>;
|
|
139
|
+
/**
|
|
140
|
+
* Sanitize the space DID for the KMS key ID
|
|
141
|
+
*
|
|
142
|
+
* @param {Type.SpaceDID} spaceDID
|
|
143
|
+
* @returns {string}
|
|
144
|
+
*/
|
|
145
|
+
sanitizeSpaceDIDForKMSKeyId(spaceDID: Type.SpaceDID): string;
|
|
146
|
+
}
|
|
147
|
+
import * as Type from '../../types.js';
|
|
148
|
+
//# sourceMappingURL=kms-crypto-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kms-crypto-adapter.d.ts","sourceRoot":"","sources":["../../../src/crypto/adapters/kms-crypto-adapter.js"],"names":[],"mappings":"AAWA;;;;;;;GAOG;AACH,yCAFgB,IAAI,CAAC,aAAa;IAGhC;;;;;;;;OAQG;IACH,6BANW,IAAI,CAAC,eAAe,wBACpB,GAAG,GAAC,MAAM,wBACV,OAAO,MAAM,IAAI,MAAM,EAAE,YAEjC;QAA0B,iBAAiB;KAC7C,EA0BA;IAnBC,sCAAsC;IAiBtC,0BAA+B;IAC/B,wFAA2D;IAG7D;;;;OAIG;IACH,oBAFW,IAAI,CAAC,QAAQ,+BAIvB;IAED;;;;;;OAMG;IACH,6BAJW,cAAc,OACd,UAAU,MACV,UAAU,gCAIpB;IAED;;;;;;;OAOG;IACH,yBALW,UAAU,MACV,UAAU,oBACV,IAAI,CAAC,gBAAgB,GACnB,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CA4B5C;IAED;;;;;;;;;OASG;IACH,kCATW,MAAM,WAEd;QAAwC,iBAAiB,EAAjD,IAAI,CAAC,iBAAiB;QACU,QAAQ,EAAxC,IAAI,CAAC,iBAAiB;QACF,aAAa,EAAjC,UAAU;QACY,WAAW,EAAjC,IAAI,CAAC,OAAO;QACoH,MAAM,EAAtI,OAAO,wBAAwB,EAAE,MAAM,CAAC,OAAO,wBAAwB,EAAE,GAAG,EAAE,OAAO,wBAAwB,EAAE,MAAM,CAAC;QACxE,QAAQ,EAAtD,OAAO,wBAAwB,EAAE,GAAG;KAC9C;;;OA4BA;IAED;;;;;;;;OAQG;IACH,gDANW,MAAM,YACN,IAAI,CAAC,QAAQ,mBACb,OAAO,mBAAmB,EAAE,KAAK,UACjC,OAAO,wBAAwB,EAAE,MAAM,CAAC,OAAO,wBAAwB,EAAE,GAAG,EAAE,OAAO,wBAAwB,EAAE,MAAM,CAAC,GACpH,OAAO,CAAC;QAAC,qBAAqB,EAAE,MAAM,CAAA;KAAC,CAAC,CA4BpD;IAED;;;;;;OAMG;IACH,8BAHW,UAAU,GACR,IAAI,CAAC,iBAAiB,CAiClC;IAED;;;OAGG;IACH,0BAHW,IAAI,CAAC,iBAAiB,GACpB,MAAM,CASlB;IAED;;;;;;;OAOG;IACH,iCALW,MAAM,gBACN,MAAM,YACN,IAAI,CAAC,cAAc,GACjB,OAAO,CAAC;QAAE,GAAG,EAAE,OAAO,+BAA+B,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC,CAoBhG;IAED;;;;;OAKG;IACH,oCAHW,IAAI,CAAC,gBAAgB,GACnB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAyB/E;IAED;;;;OAIG;IACH,mBAFa,YAAY,CAWxB;IAED;;;;;;OAMG;IACH,8BAJW,UAAU,gBACV,MAAM,GACJ,OAAO,CAAC,UAAU,CAAC,CAyB/B;IAED;;;;;OAKG;IACH,sBAHW,MAAM,GACJ,WAAW,CA6BvB;IAED,kFASC;IAED;;;;;OAKG;IACH,sCAHW,IAAI,CAAC,QAAQ,GACX,MAAM,CAIlB;CACF;sBAhZqB,gBAAgB"}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { connect } from '@ucanto/client';
|
|
2
|
+
import { CAR, HTTP } from '@ucanto/transport';
|
|
3
|
+
import { base64 } from 'multiformats/bases/base64';
|
|
4
|
+
import * as Type from '../../types.js';
|
|
5
|
+
import { EncryptionSetup, EncryptionKeyDecrypt, } from '@storacha/capabilities/space';
|
|
6
|
+
import { KMSMetadata } from '../../core/metadata/encrypted-metadata.js';
|
|
7
|
+
import * as DID from '@ipld/dag-ucan/did';
|
|
8
|
+
/**
|
|
9
|
+
* KMSCryptoAdapter implements the complete CryptoAdapter interface using KMS.
|
|
10
|
+
* It uses composition with a SymmetricCrypto implementation for file encryption/decryption
|
|
11
|
+
* and KMS via private gateway for key management operations.
|
|
12
|
+
*
|
|
13
|
+
* @class
|
|
14
|
+
* @implements {Type.CryptoAdapter}
|
|
15
|
+
*/
|
|
16
|
+
export class KMSCryptoAdapter {
|
|
17
|
+
/**
|
|
18
|
+
* Create a new KMS crypto adapter
|
|
19
|
+
*
|
|
20
|
+
* @param {Type.SymmetricCrypto} symmetricCrypto - The symmetric crypto implementation (browser or node)
|
|
21
|
+
* @param {URL|string} keyManagerServiceURL - The key manager service URL
|
|
22
|
+
* @param {`did:${string}:${string}`} keyManagerServiceDID - The key manager service DID
|
|
23
|
+
* @param {object} [options] - Optional configuration
|
|
24
|
+
* @param {boolean} [options.allowInsecureHttp] - Allow HTTP for testing (NOT for production)
|
|
25
|
+
*/
|
|
26
|
+
constructor(symmetricCrypto, keyManagerServiceURL, keyManagerServiceDID, options = {}) {
|
|
27
|
+
this.symmetricCrypto = symmetricCrypto;
|
|
28
|
+
// SECURITY: Enforce HTTPS protocol for key manager service communications (P1.1)
|
|
29
|
+
const url = keyManagerServiceURL instanceof URL
|
|
30
|
+
? keyManagerServiceURL
|
|
31
|
+
: new URL(keyManagerServiceURL);
|
|
32
|
+
const { allowInsecureHttp = false } = options;
|
|
33
|
+
if (url.protocol !== 'https:' && !allowInsecureHttp) {
|
|
34
|
+
throw new Error(`Key manager service must use HTTPS protocol for security. Received: ${url.protocol}. ` +
|
|
35
|
+
`Please update the service URL to use HTTPS (e.g., https://your-key-manager-service.com). ` +
|
|
36
|
+
`For testing only, you can pass { allowInsecureHttp: true } as the fourth parameter.`);
|
|
37
|
+
}
|
|
38
|
+
this.keyManagerServiceURL = url;
|
|
39
|
+
this.keyManagerServiceDID = DID.parse(keyManagerServiceDID);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Encrypt a stream of data using the symmetric crypto
|
|
43
|
+
*
|
|
44
|
+
* @param {Type.BlobLike} data
|
|
45
|
+
*/
|
|
46
|
+
async encryptStream(data) {
|
|
47
|
+
return this.symmetricCrypto.encryptStream(data);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Decrypt a stream of data using the symmetric crypto
|
|
51
|
+
*
|
|
52
|
+
* @param {ReadableStream} encryptedData
|
|
53
|
+
* @param {Uint8Array} key
|
|
54
|
+
* @param {Uint8Array} iv
|
|
55
|
+
*/
|
|
56
|
+
async decryptStream(encryptedData, key, iv) {
|
|
57
|
+
return this.symmetricCrypto.decryptStream(encryptedData, key, iv);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Encrypt a symmetric key using the KMS
|
|
61
|
+
*
|
|
62
|
+
* @param {Uint8Array} key
|
|
63
|
+
* @param {Uint8Array} iv
|
|
64
|
+
* @param {Type.EncryptionConfig} encryptionConfig
|
|
65
|
+
* @returns {Promise<Type.EncryptedKeyResult>}
|
|
66
|
+
*/
|
|
67
|
+
async encryptSymmetricKey(key, iv, encryptionConfig) {
|
|
68
|
+
// Step 1: Combine key and IV to encrypt a single string
|
|
69
|
+
const combinedKeyAndIV = this.symmetricCrypto.combineKeyAndIV(key, iv);
|
|
70
|
+
// Step 2: Get RSA public key from space/encryption/setup
|
|
71
|
+
const setupResponse = await this.getSpacePublicKey(encryptionConfig);
|
|
72
|
+
// Step 3: Encrypt with RSA-OAEP
|
|
73
|
+
const encryptedKey = await this.encryptWithRSA(combinedKeyAndIV, setupResponse.publicKey);
|
|
74
|
+
// Step 4: Return the encrypted key and metadata
|
|
75
|
+
return {
|
|
76
|
+
strategy: 'kms',
|
|
77
|
+
encryptedKey: base64.encode(encryptedKey), // base64-encoded for transport/storage
|
|
78
|
+
metadata: {
|
|
79
|
+
space: encryptionConfig.spaceDID,
|
|
80
|
+
kms: {
|
|
81
|
+
provider: setupResponse.provider,
|
|
82
|
+
keyId: this.sanitizeSpaceDIDForKMSKeyId(encryptionConfig.spaceDID),
|
|
83
|
+
algorithm: setupResponse.algorithm,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* @param {string} encryptedKey
|
|
90
|
+
* @param {object} configs
|
|
91
|
+
* @param {Type.DecryptionOptions} configs.decryptionOptions
|
|
92
|
+
* @param {Type.ExtractedMetadata} configs.metadata
|
|
93
|
+
* @param {Uint8Array} configs.delegationCAR
|
|
94
|
+
* @param {Type.AnyLink} configs.resourceCID
|
|
95
|
+
* @param {import('@storacha/client/types').Signer<import('@storacha/client/types').DID, import('@storacha/client/types').SigAlg>} configs.issuer
|
|
96
|
+
* @param {import('@storacha/client/types').DID} configs.audience
|
|
97
|
+
*/
|
|
98
|
+
async decryptSymmetricKey(encryptedKey, configs) {
|
|
99
|
+
// Step 1: Validate configs
|
|
100
|
+
const { decryptionOptions, metadata, issuer } = configs;
|
|
101
|
+
if (metadata.strategy !== 'kms') {
|
|
102
|
+
throw new Error('KMSCryptoAdapter can only handle KMS metadata');
|
|
103
|
+
}
|
|
104
|
+
const { spaceDID, delegationProof } = decryptionOptions;
|
|
105
|
+
if (!spaceDID || !delegationProof) {
|
|
106
|
+
throw new Error('SpaceDID and delegationProof are required');
|
|
107
|
+
}
|
|
108
|
+
if (!issuer) {
|
|
109
|
+
throw new Error('Issuer is required');
|
|
110
|
+
}
|
|
111
|
+
// Step 2: Get the decrypted key from KMS via gateway
|
|
112
|
+
const { decryptedSymmetricKey } = await this.getDecryptedSymmetricKey(encryptedKey, spaceDID, delegationProof, issuer);
|
|
113
|
+
// Step 3: Decode and split the combined key and IV
|
|
114
|
+
const combinedKeyAndIV = base64.decode(decryptedSymmetricKey);
|
|
115
|
+
return this.symmetricCrypto.splitKeyAndIV(combinedKeyAndIV);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get decrypted symmetric key in base64 string from KMS via private gateway
|
|
119
|
+
*
|
|
120
|
+
* @param {string} encryptedSymmetricKey - The encrypted symmetric key (base64-encoded)
|
|
121
|
+
* @param {Type.SpaceDID} spaceDID - The space DID
|
|
122
|
+
* @param {import('@ucanto/interface').Proof} delegationProof - The delegation proof
|
|
123
|
+
* @param {import('@storacha/client/types').Signer<import('@storacha/client/types').DID, import('@storacha/client/types').SigAlg>} issuer - The issuer
|
|
124
|
+
* @returns {Promise<{decryptedSymmetricKey: string}>} - The decrypted symmetric key (base64-encoded)
|
|
125
|
+
*/
|
|
126
|
+
async getDecryptedSymmetricKey(encryptedSymmetricKey, spaceDID, delegationProof, issuer) {
|
|
127
|
+
// Step 1: Invoke the KeyDecrypt capability passing the decryption proof
|
|
128
|
+
const result = await EncryptionKeyDecrypt.invoke({
|
|
129
|
+
issuer,
|
|
130
|
+
audience: this.keyManagerServiceDID,
|
|
131
|
+
with: spaceDID,
|
|
132
|
+
nb: {
|
|
133
|
+
key: base64.decode(encryptedSymmetricKey), // Convert base64 string to bytes
|
|
134
|
+
},
|
|
135
|
+
proofs: [delegationProof],
|
|
136
|
+
}).execute(this.newKeyManagerServiceConnection());
|
|
137
|
+
// Step 2: Handle the result
|
|
138
|
+
if (result.out.error) {
|
|
139
|
+
throw new Error(`KMS decryption failed: ${JSON.stringify(result.out.error)}`);
|
|
140
|
+
}
|
|
141
|
+
// Step 3: Return the base64-encoded decrypted key from the gateway response
|
|
142
|
+
return /** @type {{decryptedSymmetricKey: string}} */ (result.out.ok);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Extract the encrypted metadata from the CAR file
|
|
146
|
+
* KMS adapter only handles KMS format (encrypted-metadata@0.2)
|
|
147
|
+
*
|
|
148
|
+
* @param {Uint8Array} car
|
|
149
|
+
* @returns {Type.ExtractedMetadata}
|
|
150
|
+
*/
|
|
151
|
+
extractEncryptedMetadata(car) {
|
|
152
|
+
const kmsContentResult = KMSMetadata.extract(car);
|
|
153
|
+
if (kmsContentResult.error) {
|
|
154
|
+
throw kmsContentResult.error;
|
|
155
|
+
}
|
|
156
|
+
const kmsContent = kmsContentResult.ok.toJSON();
|
|
157
|
+
// Validate it's KMS format
|
|
158
|
+
if (!kmsContent.encryptedSymmetricKey ||
|
|
159
|
+
!kmsContent.space ||
|
|
160
|
+
!kmsContent.kms) {
|
|
161
|
+
throw new Error('Invalid KMS metadata format - missing encryptedSymmetricKey, space, or kms fields');
|
|
162
|
+
}
|
|
163
|
+
// Return with strategy identifier
|
|
164
|
+
return {
|
|
165
|
+
strategy: 'kms',
|
|
166
|
+
encryptedDataCID: kmsContent.encryptedDataCID,
|
|
167
|
+
encryptedSymmetricKey: kmsContent.encryptedSymmetricKey,
|
|
168
|
+
space: /** @type {Type.SpaceDID} */ (kmsContent.space),
|
|
169
|
+
kms: {
|
|
170
|
+
provider: kmsContent.kms.provider,
|
|
171
|
+
keyId: kmsContent.kms.keyId,
|
|
172
|
+
algorithm: kmsContent.kms.algorithm,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* @param {Type.ExtractedMetadata} metadata
|
|
178
|
+
* @returns {string}
|
|
179
|
+
*/
|
|
180
|
+
getEncryptedKey(metadata) {
|
|
181
|
+
// For KMS metadata, we need to handle the different structure
|
|
182
|
+
if (metadata.strategy === 'kms') {
|
|
183
|
+
return /** @type {Type.KMSExtractedMetadata} */ (metadata)
|
|
184
|
+
.encryptedSymmetricKey;
|
|
185
|
+
}
|
|
186
|
+
throw new Error('KMSCryptoAdapter can only handle KMS metadata');
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Encode metadata for upload
|
|
190
|
+
*
|
|
191
|
+
* @param {string} encryptedDataCID - The CID of the encrypted data
|
|
192
|
+
* @param {string} encryptedKey - The encrypted key
|
|
193
|
+
* @param {Type.KMSKeyMetadata} metadata - The metadata to encode
|
|
194
|
+
* @returns {Promise<{ cid: import('@storacha/upload-client/types').AnyLink, bytes: Uint8Array }>} - The encoded metadata
|
|
195
|
+
*/
|
|
196
|
+
async encodeMetadata(encryptedDataCID, encryptedKey, metadata) {
|
|
197
|
+
const kmsKeyMetadata =
|
|
198
|
+
/** @type {import('../../types.js').KMSKeyMetadata} */ (metadata);
|
|
199
|
+
/** @type {Type.KMSMetadataInput} */
|
|
200
|
+
const uploadData = {
|
|
201
|
+
encryptedDataCID,
|
|
202
|
+
encryptedSymmetricKey: encryptedKey,
|
|
203
|
+
space: kmsKeyMetadata.space,
|
|
204
|
+
kms: {
|
|
205
|
+
provider: kmsKeyMetadata.kms.provider,
|
|
206
|
+
keyId: kmsKeyMetadata.kms.keyId,
|
|
207
|
+
algorithm: kmsKeyMetadata.kms.algorithm,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
const kmsMetadata = KMSMetadata.create(uploadData);
|
|
211
|
+
return await kmsMetadata.archiveBlock();
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get the RSA public key from the space/encryption/setup
|
|
215
|
+
*
|
|
216
|
+
* @param {Type.EncryptionConfig} encryptionConfig
|
|
217
|
+
* @returns {Promise<{ publicKey: string, provider: string, algorithm: string }>}
|
|
218
|
+
*/
|
|
219
|
+
async getSpacePublicKey(encryptionConfig) {
|
|
220
|
+
// Step 1: Invoke the EncryptionSetup capability
|
|
221
|
+
const setupResult = await EncryptionSetup.invoke({
|
|
222
|
+
issuer: encryptionConfig.issuer,
|
|
223
|
+
audience: this.keyManagerServiceDID,
|
|
224
|
+
with: encryptionConfig.spaceDID,
|
|
225
|
+
nb: {
|
|
226
|
+
location: encryptionConfig.location,
|
|
227
|
+
keyring: encryptionConfig.keyring,
|
|
228
|
+
},
|
|
229
|
+
}).execute(this.newKeyManagerServiceConnection());
|
|
230
|
+
// Step 2: Handle the result
|
|
231
|
+
if (setupResult.out.error) {
|
|
232
|
+
throw new Error(`Failed to get public key: ${JSON.stringify(setupResult.out.error)}`);
|
|
233
|
+
}
|
|
234
|
+
// Step 3: Return the public key and key reference
|
|
235
|
+
return /** @type {{ publicKey: string, provider: string, algorithm: string }} */ (setupResult.out.ok);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get the Web Crypto API SubtleCrypto interface (universal compatibility)
|
|
239
|
+
*
|
|
240
|
+
* @returns {SubtleCrypto} - The SubtleCrypto interface
|
|
241
|
+
*/
|
|
242
|
+
getSubtleCrypto() {
|
|
243
|
+
// Web Crypto API is available in modern browsers (secure contexts) and Node.js 16+
|
|
244
|
+
if (globalThis.crypto?.subtle) {
|
|
245
|
+
return globalThis.crypto.subtle;
|
|
246
|
+
}
|
|
247
|
+
throw new Error('Web Crypto API (SubtleCrypto) not available. Ensure you are running in a secure context (HTTPS) or Node.js 16+.');
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Encrypt data with RSA-OAEP using the public key
|
|
251
|
+
*
|
|
252
|
+
* @param {Uint8Array} dataToEncrypt
|
|
253
|
+
* @param {string} publicKeyPem
|
|
254
|
+
* @returns {Promise<Uint8Array>}
|
|
255
|
+
*/
|
|
256
|
+
async encryptWithRSA(dataToEncrypt, publicKeyPem) {
|
|
257
|
+
const subtle = this.getSubtleCrypto();
|
|
258
|
+
// Step 1. Import the PEM public key
|
|
259
|
+
const publicKey = await subtle.importKey('spki', this.pemToArrayBuffer(publicKeyPem), {
|
|
260
|
+
name: 'RSA-OAEP',
|
|
261
|
+
hash: 'SHA-256',
|
|
262
|
+
}, false, ['encrypt']);
|
|
263
|
+
// Step 2. Encrypt the raw data directly
|
|
264
|
+
const encrypted = await subtle.encrypt({ name: 'RSA-OAEP' }, publicKey, dataToEncrypt);
|
|
265
|
+
return new Uint8Array(encrypted);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Convert PEM-encoded public key to ArrayBuffer for Web Crypto API
|
|
269
|
+
*
|
|
270
|
+
* @param {string} pem - PEM-encoded public key string
|
|
271
|
+
* @returns {ArrayBuffer} - DER-encoded key data for crypto.subtle.importKey()
|
|
272
|
+
*/
|
|
273
|
+
pemToArrayBuffer(pem) {
|
|
274
|
+
// Strip PEM headers, footers, and whitespace to get base64 DER data
|
|
275
|
+
const base64String = pem
|
|
276
|
+
.replace('-----BEGIN PUBLIC KEY-----', '')
|
|
277
|
+
.replace('-----END PUBLIC KEY-----', '')
|
|
278
|
+
.replace(/\s/g, '');
|
|
279
|
+
// For Node.js environment, use Buffer for standard base64 decoding
|
|
280
|
+
if (typeof Buffer !== 'undefined') {
|
|
281
|
+
return Buffer.from(base64String, 'base64');
|
|
282
|
+
}
|
|
283
|
+
// For browser environment, use atob for standard base64 decoding
|
|
284
|
+
let binaryString;
|
|
285
|
+
if (typeof globalThis !== 'undefined' && globalThis.atob) {
|
|
286
|
+
binaryString = globalThis.atob(base64String);
|
|
287
|
+
}
|
|
288
|
+
else if (typeof Buffer !== 'undefined') {
|
|
289
|
+
// @ts-ignore - Buffer exists in Node.js environment
|
|
290
|
+
binaryString = Buffer.from(base64String, 'base64').toString('binary');
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
throw new Error('Neither atob nor Buffer available for base64 decoding');
|
|
294
|
+
}
|
|
295
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
296
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
297
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
298
|
+
}
|
|
299
|
+
return bytes;
|
|
300
|
+
}
|
|
301
|
+
newKeyManagerServiceConnection() {
|
|
302
|
+
return connect({
|
|
303
|
+
id: this.keyManagerServiceDID,
|
|
304
|
+
codec: CAR.outbound,
|
|
305
|
+
channel: HTTP.open({
|
|
306
|
+
url: this.keyManagerServiceURL,
|
|
307
|
+
method: 'POST',
|
|
308
|
+
}),
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Sanitize the space DID for the KMS key ID
|
|
313
|
+
*
|
|
314
|
+
* @param {Type.SpaceDID} spaceDID
|
|
315
|
+
* @returns {string}
|
|
316
|
+
*/
|
|
317
|
+
sanitizeSpaceDIDForKMSKeyId(spaceDID) {
|
|
318
|
+
return spaceDID.replace(/^did:key:/, '');
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=kms-crypto-adapter.js.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LitCryptoAdapter implements the complete CryptoAdapter interface using Lit Protocol.
|
|
3
|
+
* It uses composition with a SymmetricCrypto implementation for file encryption/decryption
|
|
4
|
+
* and Lit Protocol for key management operations.
|
|
5
|
+
*
|
|
6
|
+
* @class
|
|
7
|
+
* @implements {Type.CryptoAdapter}
|
|
8
|
+
*/
|
|
9
|
+
export class LitCryptoAdapter implements Type.CryptoAdapter {
|
|
10
|
+
/**
|
|
11
|
+
* Create a new Lit crypto adapter
|
|
12
|
+
*
|
|
13
|
+
* @param {Type.SymmetricCrypto} symmetricCrypto - The symmetric crypto implementation (browser or node)
|
|
14
|
+
* @param {import('@lit-protocol/lit-node-client').LitNodeClient} litClient - The Lit client instance
|
|
15
|
+
*/
|
|
16
|
+
constructor(symmetricCrypto: Type.SymmetricCrypto, litClient: import("@lit-protocol/lit-node-client").LitNodeClient);
|
|
17
|
+
symmetricCrypto: Type.SymmetricCrypto;
|
|
18
|
+
litClient: import("@lit-protocol/lit-node-client").LitNodeClient;
|
|
19
|
+
/**
|
|
20
|
+
* Encrypt a stream of data using the symmetric crypto implementation
|
|
21
|
+
*
|
|
22
|
+
* @param {Type.BlobLike} data - The data to encrypt
|
|
23
|
+
* @returns {Promise<Type.EncryptOutput>} - The encrypted data
|
|
24
|
+
*/
|
|
25
|
+
encryptStream(data: Type.BlobLike): Promise<Type.EncryptOutput>;
|
|
26
|
+
/**
|
|
27
|
+
* Decrypt a stream of data using the symmetric crypto implementation
|
|
28
|
+
*
|
|
29
|
+
* @param {ReadableStream} encryptedData - The encrypted data to decrypt
|
|
30
|
+
* @param {Uint8Array} key - The key to use for decryption
|
|
31
|
+
* @param {Uint8Array} iv - The initialization vector to use for decryption
|
|
32
|
+
* @returns {Promise<ReadableStream>} - The decrypted data
|
|
33
|
+
*/
|
|
34
|
+
decryptStream(encryptedData: ReadableStream, key: Uint8Array, iv: Uint8Array): Promise<ReadableStream>;
|
|
35
|
+
/**
|
|
36
|
+
* Encrypt a symmetric key using the Lit crypto adapter
|
|
37
|
+
*
|
|
38
|
+
* @param {Uint8Array} key - The symmetric key to encrypt
|
|
39
|
+
* @param {Uint8Array} iv - The initialization vector to encrypt
|
|
40
|
+
* @param {Type.EncryptionConfig} encryptionConfig - The encryption configuration
|
|
41
|
+
* @returns {Promise<Type.EncryptedKeyResult>} - The encrypted key result
|
|
42
|
+
*/
|
|
43
|
+
encryptSymmetricKey(key: Uint8Array, iv: Uint8Array, encryptionConfig: Type.EncryptionConfig): Promise<Type.EncryptedKeyResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Decrypt a symmetric key using the Lit crypto adapter
|
|
46
|
+
*
|
|
47
|
+
* @param {string} encryptedKey - The encrypted key to decrypt
|
|
48
|
+
* @param {object} configs - The decryption configuration
|
|
49
|
+
* @param {Type.DecryptionOptions} configs.decryptionOptions - The decryption options
|
|
50
|
+
* @param {Type.ExtractedMetadata} configs.metadata - The extracted metadata
|
|
51
|
+
* @param {Uint8Array} configs.delegationCAR - The delegation CAR
|
|
52
|
+
* @param {Type.AnyLink} configs.resourceCID - The resource CID
|
|
53
|
+
* @param {import('@storacha/client/types').Signer<import('@storacha/client/types').DID, import('@storacha/client/types').SigAlg>} configs.issuer - The issuer
|
|
54
|
+
* @param {import('@storacha/client/types').DID} configs.audience - The audience
|
|
55
|
+
* @returns {Promise<{ key: Uint8Array, iv: Uint8Array }>} - The decrypted key and IV
|
|
56
|
+
*/
|
|
57
|
+
decryptSymmetricKey(encryptedKey: string, configs: {
|
|
58
|
+
decryptionOptions: Type.DecryptionOptions;
|
|
59
|
+
metadata: Type.ExtractedMetadata;
|
|
60
|
+
delegationCAR: Uint8Array;
|
|
61
|
+
resourceCID: Type.AnyLink;
|
|
62
|
+
issuer: import("@storacha/client/types").Signer<import("@storacha/client/types").DID, import("@storacha/client/types").SigAlg>;
|
|
63
|
+
audience: import("@storacha/client/types").DID;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
key: Uint8Array;
|
|
66
|
+
iv: Uint8Array;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Extract encrypted metadata from a CAR file
|
|
70
|
+
*
|
|
71
|
+
* @param {Uint8Array} car - The CAR file to extract metadata from
|
|
72
|
+
* @returns {Type.ExtractedMetadata} - The extracted metadata
|
|
73
|
+
*/
|
|
74
|
+
extractEncryptedMetadata(car: Uint8Array): Type.ExtractedMetadata;
|
|
75
|
+
/**
|
|
76
|
+
* Get the encrypted key from the metadata
|
|
77
|
+
*
|
|
78
|
+
* @param {Type.ExtractedMetadata} metadata - The metadata to get the encrypted key from
|
|
79
|
+
* @returns {string} - The encrypted key
|
|
80
|
+
*/
|
|
81
|
+
getEncryptedKey(metadata: Type.ExtractedMetadata): string;
|
|
82
|
+
/**
|
|
83
|
+
* Encode metadata for upload
|
|
84
|
+
*
|
|
85
|
+
* @param {string} encryptedDataCID - The CID of the encrypted data
|
|
86
|
+
* @param {string} encryptedKey - The encrypted key
|
|
87
|
+
* @param {Type.LitKeyMetadata} metadata - The metadata to encode
|
|
88
|
+
* @returns {Promise<{ cid: import('@storacha/upload-client/types').AnyLink, bytes: Uint8Array }>} - The encoded metadata
|
|
89
|
+
*/
|
|
90
|
+
encodeMetadata(encryptedDataCID: string, encryptedKey: string, metadata: Type.LitKeyMetadata): Promise<{
|
|
91
|
+
cid: import("@storacha/upload-client/types").AnyLink;
|
|
92
|
+
bytes: Uint8Array;
|
|
93
|
+
}>;
|
|
94
|
+
}
|
|
95
|
+
import * as Type from '../../types.js';
|
|
96
|
+
//# sourceMappingURL=lit-crypto-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lit-crypto-adapter.d.ts","sourceRoot":"","sources":["../../../src/crypto/adapters/lit-crypto-adapter.js"],"names":[],"mappings":"AAMA;;;;;;;GAOG;AACH,yCAFgB,IAAI,CAAC,aAAa;IAGhC;;;;;OAKG;IACH,6BAHW,IAAI,CAAC,eAAe,aACpB,OAAO,+BAA+B,EAAE,aAAa,EAK/D;IAFC,sCAAsC;IACtC,iEAA0B;IAG5B;;;;;OAKG;IACH,oBAHW,IAAI,CAAC,QAAQ,GACX,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAIvC;IAED;;;;;;;OAOG;IACH,6BALW,cAAc,OACd,UAAU,MACV,UAAU,GACR,OAAO,CAAC,cAAc,CAAC,CAInC;IAED;;;;;;;OAOG;IACH,yBALW,UAAU,MACV,UAAU,oBACV,IAAI,CAAC,gBAAgB,GACnB,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAgC5C;IAED;;;;;;;;;;;;OAYG;IACH,kCAVW,MAAM,WAEd;QAAwC,iBAAiB,EAAjD,IAAI,CAAC,iBAAiB;QACU,QAAQ,EAAxC,IAAI,CAAC,iBAAiB;QACF,aAAa,EAAjC,UAAU;QACY,WAAW,EAAjC,IAAI,CAAC,OAAO;QACoH,MAAM,EAAtI,OAAO,wBAAwB,EAAE,MAAM,CAAC,OAAO,wBAAwB,EAAE,GAAG,EAAE,OAAO,wBAAwB,EAAE,MAAM,CAAC;QACxE,QAAQ,EAAtD,OAAO,wBAAwB,EAAE,GAAG;KAC5C,GAAU,OAAO,CAAC;QAAE,GAAG,EAAE,UAAU,CAAC;QAAC,EAAE,EAAE,UAAU,CAAA;KAAE,CAAC,CAsFxD;IAED;;;;;OAKG;IACH,8BAHW,UAAU,GACR,IAAI,CAAC,iBAAiB,CA4BlC;IAED;;;;;OAKG;IACH,0BAHW,IAAI,CAAC,iBAAiB,GACpB,MAAM,CAOlB;IAED;;;;;;;OAOG;IACH,iCALW,MAAM,gBACN,MAAM,YACN,IAAI,CAAC,cAAc,GACjB,OAAO,CAAC;QAAE,GAAG,EAAE,OAAO,+BAA+B,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC,CAehG;CACF;sBA5PqB,gBAAgB"}
|