@tnid/encryption 0.0.4 → 0.0.5
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 +15 -25
- package/esm/bits.js +1 -1
- package/esm/encryption.d.ts +7 -6
- package/esm/encryption.d.ts.map +1 -1
- package/esm/encryption.js +9 -23
- package/package.json +2 -2
- package/script/bits.js +1 -1
- package/script/encryption.d.ts +7 -6
- package/script/encryption.d.ts.map +1 -1
- package/script/encryption.js +9 -23
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @tnid/encryption
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Encrypt V0 TNIDs to V1 to hide timestamp information.
|
|
4
4
|
|
|
5
5
|
## Why Encrypt TNIDs?
|
|
6
6
|
|
|
@@ -62,13 +62,7 @@ const decrypted = await decryptV1ToV0(v1, key);
|
|
|
62
62
|
|
|
63
63
|
## How It Works
|
|
64
64
|
|
|
65
|
-
The encryption
|
|
66
|
-
|
|
67
|
-
- The TNID name (unchanged)
|
|
68
|
-
- The UUID version/variant bits (valid UUIDv8)
|
|
69
|
-
- The overall 128-bit structure
|
|
70
|
-
|
|
71
|
-
The TNID variant changes from V0 to V1, making the encrypted ID indistinguishable from a randomly generated V1 TNID.
|
|
65
|
+
The encryption converts the 100 payload bits while preserving the TNID structure. The result is a valid V1 TNID that is indistinguishable from a randomly generated one.
|
|
72
66
|
|
|
73
67
|
## API Reference
|
|
74
68
|
|
|
@@ -94,26 +88,27 @@ const bytes: Uint8Array = key.asBytes();
|
|
|
94
88
|
Encrypts a V0 TNID to V1, hiding timestamp information.
|
|
95
89
|
|
|
96
90
|
```typescript
|
|
97
|
-
const
|
|
91
|
+
const v0: UserId = UserId.new_v0();
|
|
92
|
+
const v1: UserId = await encryptV0ToV1(v0, key); // Type preserved!
|
|
98
93
|
```
|
|
99
94
|
|
|
100
|
-
- **Input**: V0 TNID
|
|
101
|
-
- **Output**: V1 TNID
|
|
95
|
+
- **Input**: V0 TNID (any typed TNID or `DynamicTnid`)
|
|
96
|
+
- **Output**: V1 TNID (same type as input)
|
|
102
97
|
- **Idempotent**: If input is already V1, returns it unchanged
|
|
103
|
-
- **Throws**: `EncryptionError` if
|
|
98
|
+
- **Throws**: `EncryptionError` if variant is unsupported (v2/v3)
|
|
104
99
|
|
|
105
100
|
### `decryptV1ToV0(tnid, key)`
|
|
106
101
|
|
|
107
102
|
Decrypts a V1 TNID back to V0, recovering timestamp information.
|
|
108
103
|
|
|
109
104
|
```typescript
|
|
110
|
-
const
|
|
105
|
+
const decrypted: UserId = await decryptV1ToV0(v1, key); // Type preserved!
|
|
111
106
|
```
|
|
112
107
|
|
|
113
|
-
- **Input**: V1 TNID
|
|
114
|
-
- **Output**: V0 TNID
|
|
108
|
+
- **Input**: V1 TNID (any typed TNID or `DynamicTnid`)
|
|
109
|
+
- **Output**: V0 TNID (same type as input)
|
|
115
110
|
- **Idempotent**: If input is already V0, returns it unchanged
|
|
116
|
-
- **Throws**: `EncryptionError` if
|
|
111
|
+
- **Throws**: `EncryptionError` if variant is unsupported (v2/v3)
|
|
117
112
|
|
|
118
113
|
### Error Classes
|
|
119
114
|
|
|
@@ -128,17 +123,12 @@ try {
|
|
|
128
123
|
console.log("Invalid key:", e.message);
|
|
129
124
|
}
|
|
130
125
|
}
|
|
131
|
-
|
|
132
|
-
// EncryptionError - encryption/decryption failed
|
|
133
|
-
try {
|
|
134
|
-
await encryptV0ToV1("invalid-tnid", key);
|
|
135
|
-
} catch (e) {
|
|
136
|
-
if (e instanceof EncryptionError) {
|
|
137
|
-
console.log("Encryption failed:", e.message);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
126
|
```
|
|
141
127
|
|
|
128
|
+
## Implementation Details
|
|
129
|
+
|
|
130
|
+
Uses FF1 format-preserving encryption (NIST SP 800-38G) with AES-128, which allows encrypting the 100 payload bits while maintaining the exact same bit length. This implementation is bit-compatible with the Rust TNID library.
|
|
131
|
+
|
|
142
132
|
## Note
|
|
143
133
|
|
|
144
134
|
The encryption functionality is not part of the TNID specification. Encrypted TNIDs are standard V1 TNIDs and remain fully compatible with any TNID implementation.
|
package/esm/bits.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* These functions extract and expand the 100 Payload bits that are
|
|
5
5
|
* encrypted/decrypted, matching the Rust implementation exactly.
|
|
6
6
|
*/
|
|
7
|
-
// Mask for the right-most Payload bits section (bits 0-
|
|
7
|
+
// Mask for the right-most Payload bits section (bits 0-59, 60 bits)
|
|
8
8
|
export const RIGHT_SECRET_DATA_SECTION_MASK = 0x00000000000000000fffffffffffffffn;
|
|
9
9
|
// Mask for the middle Payload bits section (bits 64-75, 12 bits)
|
|
10
10
|
export const MIDDLE_SECRET_DATA_SECTION_MASK = 0x0000000000000fff0000000000000000n;
|
package/esm/encryption.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Provides functions to convert V0 (time-ordered) TNIDs to V1 (random-looking)
|
|
5
5
|
* TNIDs and vice versa, hiding timestamp information while remaining reversible.
|
|
6
6
|
*/
|
|
7
|
+
import { DynamicTnid } from "@tnid/core";
|
|
7
8
|
/**
|
|
8
9
|
* Error when creating an EncryptionKey.
|
|
9
10
|
*/
|
|
@@ -38,19 +39,19 @@ export declare class EncryptionKey {
|
|
|
38
39
|
/**
|
|
39
40
|
* Encrypts a V0 TNID to V1, hiding timestamp information.
|
|
40
41
|
*
|
|
41
|
-
* @param tnid The V0 TNID
|
|
42
|
+
* @param tnid The V0 TNID to encrypt
|
|
42
43
|
* @param key The encryption key
|
|
43
|
-
* @returns The encrypted V1 TNID
|
|
44
|
+
* @returns The encrypted V1 TNID (same type as input)
|
|
44
45
|
* @throws EncryptionError if the TNID is not V0 or is invalid
|
|
45
46
|
*/
|
|
46
|
-
export declare function encryptV0ToV1(tnid:
|
|
47
|
+
export declare function encryptV0ToV1<T extends DynamicTnid>(tnid: T, key: EncryptionKey): Promise<T>;
|
|
47
48
|
/**
|
|
48
49
|
* Decrypts a V1 TNID back to V0, recovering timestamp information.
|
|
49
50
|
*
|
|
50
|
-
* @param tnid The V1 TNID
|
|
51
|
+
* @param tnid The V1 TNID to decrypt
|
|
51
52
|
* @param key The encryption key (must match the one used for encryption)
|
|
52
|
-
* @returns The decrypted V0 TNID
|
|
53
|
+
* @returns The decrypted V0 TNID (same type as input)
|
|
53
54
|
* @throws EncryptionError if the TNID is not V1 or is invalid
|
|
54
55
|
*/
|
|
55
|
-
export declare function decryptV1ToV0(tnid:
|
|
56
|
+
export declare function decryptV1ToV0<T extends DynamicTnid>(tnid: T, key: EncryptionKey): Promise<T>;
|
|
56
57
|
//# sourceMappingURL=encryption.d.ts.map
|
package/esm/encryption.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAiBzC;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IAEnC,OAAO;IAIP;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa;IASlD;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa;IAsB1C;;OAEG;IACH,OAAO,IAAI,UAAU;CAGtB;AA2DD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CA8BlG;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CA8BlG"}
|
package/esm/encryption.js
CHANGED
|
@@ -74,16 +74,14 @@ export class EncryptionKey {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
|
-
* Convert TNID
|
|
77
|
+
* Convert TNID to 128-bit value.
|
|
78
78
|
*/
|
|
79
79
|
function tnidToValue(tnid) {
|
|
80
|
-
|
|
81
|
-
const parsed = DynamicTnid.parse(tnid);
|
|
82
|
-
const uuid = DynamicTnid.toUuidString(parsed);
|
|
80
|
+
const uuid = DynamicTnid.toUuidString(tnid);
|
|
83
81
|
return parseUuidStringToValue(uuid);
|
|
84
82
|
}
|
|
85
83
|
/**
|
|
86
|
-
* Convert 128-bit value back to TNID
|
|
84
|
+
* Convert 128-bit value back to TNID.
|
|
87
85
|
*/
|
|
88
86
|
function valueToTnid(value) {
|
|
89
87
|
return valueToTnidString(value);
|
|
@@ -123,19 +121,13 @@ async function decryptPayload(payload, key) {
|
|
|
123
121
|
/**
|
|
124
122
|
* Encrypts a V0 TNID to V1, hiding timestamp information.
|
|
125
123
|
*
|
|
126
|
-
* @param tnid The V0 TNID
|
|
124
|
+
* @param tnid The V0 TNID to encrypt
|
|
127
125
|
* @param key The encryption key
|
|
128
|
-
* @returns The encrypted V1 TNID
|
|
126
|
+
* @returns The encrypted V1 TNID (same type as input)
|
|
129
127
|
* @throws EncryptionError if the TNID is not V0 or is invalid
|
|
130
128
|
*/
|
|
131
129
|
export async function encryptV0ToV1(tnid, key) {
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
value = tnidToValue(tnid);
|
|
135
|
-
}
|
|
136
|
-
catch (e) {
|
|
137
|
-
throw new EncryptionError(`Invalid TNID: ${e.message}`);
|
|
138
|
-
}
|
|
130
|
+
const value = tnidToValue(tnid);
|
|
139
131
|
const variant = extractVariantFromValue(value);
|
|
140
132
|
if (variant === "v1") {
|
|
141
133
|
// Already V1, return unchanged
|
|
@@ -159,19 +151,13 @@ export async function encryptV0ToV1(tnid, key) {
|
|
|
159
151
|
/**
|
|
160
152
|
* Decrypts a V1 TNID back to V0, recovering timestamp information.
|
|
161
153
|
*
|
|
162
|
-
* @param tnid The V1 TNID
|
|
154
|
+
* @param tnid The V1 TNID to decrypt
|
|
163
155
|
* @param key The encryption key (must match the one used for encryption)
|
|
164
|
-
* @returns The decrypted V0 TNID
|
|
156
|
+
* @returns The decrypted V0 TNID (same type as input)
|
|
165
157
|
* @throws EncryptionError if the TNID is not V1 or is invalid
|
|
166
158
|
*/
|
|
167
159
|
export async function decryptV1ToV0(tnid, key) {
|
|
168
|
-
|
|
169
|
-
try {
|
|
170
|
-
value = tnidToValue(tnid);
|
|
171
|
-
}
|
|
172
|
-
catch (e) {
|
|
173
|
-
throw new EncryptionError(`Invalid TNID: ${e.message}`);
|
|
174
|
-
}
|
|
160
|
+
const value = tnidToValue(tnid);
|
|
175
161
|
const variant = extractVariantFromValue(value);
|
|
176
162
|
if (variant === "v0") {
|
|
177
163
|
// Already V0, return unchanged
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tnid/encryption",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Format-preserving encryption for TNIDs - convert time-ordered IDs to random-looking IDs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"uuid",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"node": ">=20"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@tnid/core": "^0.0.
|
|
37
|
+
"@tnid/core": "^0.0.5"
|
|
38
38
|
},
|
|
39
39
|
"_generatedBy": "dnt@dev"
|
|
40
40
|
}
|
package/script/bits.js
CHANGED
|
@@ -13,7 +13,7 @@ exports.toHexDigits = toHexDigits;
|
|
|
13
13
|
exports.fromHexDigits = fromHexDigits;
|
|
14
14
|
exports.getVariant = getVariant;
|
|
15
15
|
exports.setVariant = setVariant;
|
|
16
|
-
// Mask for the right-most Payload bits section (bits 0-
|
|
16
|
+
// Mask for the right-most Payload bits section (bits 0-59, 60 bits)
|
|
17
17
|
exports.RIGHT_SECRET_DATA_SECTION_MASK = 0x00000000000000000fffffffffffffffn;
|
|
18
18
|
// Mask for the middle Payload bits section (bits 64-75, 12 bits)
|
|
19
19
|
exports.MIDDLE_SECRET_DATA_SECTION_MASK = 0x0000000000000fff0000000000000000n;
|
package/script/encryption.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Provides functions to convert V0 (time-ordered) TNIDs to V1 (random-looking)
|
|
5
5
|
* TNIDs and vice versa, hiding timestamp information while remaining reversible.
|
|
6
6
|
*/
|
|
7
|
+
import { DynamicTnid } from "@tnid/core";
|
|
7
8
|
/**
|
|
8
9
|
* Error when creating an EncryptionKey.
|
|
9
10
|
*/
|
|
@@ -38,19 +39,19 @@ export declare class EncryptionKey {
|
|
|
38
39
|
/**
|
|
39
40
|
* Encrypts a V0 TNID to V1, hiding timestamp information.
|
|
40
41
|
*
|
|
41
|
-
* @param tnid The V0 TNID
|
|
42
|
+
* @param tnid The V0 TNID to encrypt
|
|
42
43
|
* @param key The encryption key
|
|
43
|
-
* @returns The encrypted V1 TNID
|
|
44
|
+
* @returns The encrypted V1 TNID (same type as input)
|
|
44
45
|
* @throws EncryptionError if the TNID is not V0 or is invalid
|
|
45
46
|
*/
|
|
46
|
-
export declare function encryptV0ToV1(tnid:
|
|
47
|
+
export declare function encryptV0ToV1<T extends DynamicTnid>(tnid: T, key: EncryptionKey): Promise<T>;
|
|
47
48
|
/**
|
|
48
49
|
* Decrypts a V1 TNID back to V0, recovering timestamp information.
|
|
49
50
|
*
|
|
50
|
-
* @param tnid The V1 TNID
|
|
51
|
+
* @param tnid The V1 TNID to decrypt
|
|
51
52
|
* @param key The encryption key (must match the one used for encryption)
|
|
52
|
-
* @returns The decrypted V0 TNID
|
|
53
|
+
* @returns The decrypted V0 TNID (same type as input)
|
|
53
54
|
* @throws EncryptionError if the TNID is not V1 or is invalid
|
|
54
55
|
*/
|
|
55
|
-
export declare function decryptV1ToV0(tnid:
|
|
56
|
+
export declare function decryptV1ToV0<T extends DynamicTnid>(tnid: T, key: EncryptionKey): Promise<T>;
|
|
56
57
|
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAiBzC;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IAEnC,OAAO;IAIP;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa;IASlD;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa;IAsB1C;;OAEG;IACH,OAAO,IAAI,UAAU;CAGtB;AA2DD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CA8BlG;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CA8BlG"}
|
package/script/encryption.js
CHANGED
|
@@ -82,16 +82,14 @@ class EncryptionKey {
|
|
|
82
82
|
}
|
|
83
83
|
exports.EncryptionKey = EncryptionKey;
|
|
84
84
|
/**
|
|
85
|
-
* Convert TNID
|
|
85
|
+
* Convert TNID to 128-bit value.
|
|
86
86
|
*/
|
|
87
87
|
function tnidToValue(tnid) {
|
|
88
|
-
|
|
89
|
-
const parsed = core_1.DynamicTnid.parse(tnid);
|
|
90
|
-
const uuid = core_1.DynamicTnid.toUuidString(parsed);
|
|
88
|
+
const uuid = core_1.DynamicTnid.toUuidString(tnid);
|
|
91
89
|
return (0, uuid_1.parseUuidStringToValue)(uuid);
|
|
92
90
|
}
|
|
93
91
|
/**
|
|
94
|
-
* Convert 128-bit value back to TNID
|
|
92
|
+
* Convert 128-bit value back to TNID.
|
|
95
93
|
*/
|
|
96
94
|
function valueToTnid(value) {
|
|
97
95
|
return (0, uuid_1.valueToTnidString)(value);
|
|
@@ -131,19 +129,13 @@ async function decryptPayload(payload, key) {
|
|
|
131
129
|
/**
|
|
132
130
|
* Encrypts a V0 TNID to V1, hiding timestamp information.
|
|
133
131
|
*
|
|
134
|
-
* @param tnid The V0 TNID
|
|
132
|
+
* @param tnid The V0 TNID to encrypt
|
|
135
133
|
* @param key The encryption key
|
|
136
|
-
* @returns The encrypted V1 TNID
|
|
134
|
+
* @returns The encrypted V1 TNID (same type as input)
|
|
137
135
|
* @throws EncryptionError if the TNID is not V0 or is invalid
|
|
138
136
|
*/
|
|
139
137
|
async function encryptV0ToV1(tnid, key) {
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
value = tnidToValue(tnid);
|
|
143
|
-
}
|
|
144
|
-
catch (e) {
|
|
145
|
-
throw new EncryptionError(`Invalid TNID: ${e.message}`);
|
|
146
|
-
}
|
|
138
|
+
const value = tnidToValue(tnid);
|
|
147
139
|
const variant = (0, uuid_1.extractVariantFromValue)(value);
|
|
148
140
|
if (variant === "v1") {
|
|
149
141
|
// Already V1, return unchanged
|
|
@@ -167,19 +159,13 @@ async function encryptV0ToV1(tnid, key) {
|
|
|
167
159
|
/**
|
|
168
160
|
* Decrypts a V1 TNID back to V0, recovering timestamp information.
|
|
169
161
|
*
|
|
170
|
-
* @param tnid The V1 TNID
|
|
162
|
+
* @param tnid The V1 TNID to decrypt
|
|
171
163
|
* @param key The encryption key (must match the one used for encryption)
|
|
172
|
-
* @returns The decrypted V0 TNID
|
|
164
|
+
* @returns The decrypted V0 TNID (same type as input)
|
|
173
165
|
* @throws EncryptionError if the TNID is not V1 or is invalid
|
|
174
166
|
*/
|
|
175
167
|
async function decryptV1ToV0(tnid, key) {
|
|
176
|
-
|
|
177
|
-
try {
|
|
178
|
-
value = tnidToValue(tnid);
|
|
179
|
-
}
|
|
180
|
-
catch (e) {
|
|
181
|
-
throw new EncryptionError(`Invalid TNID: ${e.message}`);
|
|
182
|
-
}
|
|
168
|
+
const value = tnidToValue(tnid);
|
|
183
169
|
const variant = (0, uuid_1.extractVariantFromValue)(value);
|
|
184
170
|
if (variant === "v0") {
|
|
185
171
|
// Already V0, return unchanged
|