11import { expect } from 'chai' ;
22import { Subtle } from 'react-native-quick-crypto' ;
3+ import type { SubtleAlgorithm } from 'react-native-quick-crypto' ;
34import { test } from '../util' ;
45
56const SUITE = 'subtle.supports' ;
67
78// --- Encrypt ---
8- test ( SUITE , 'encrypt: AES-GCM is supported' , ( ) => {
9- expect ( Subtle . supports ( 'encrypt' , 'AES-GCM' ) ) . to . equal ( true ) ;
9+ // Strict WebIDL normalization (#1025): AeadParams.iv is required, so passing
10+ // just the string returns false. Full params are needed to assert support.
11+ test ( SUITE , 'encrypt: AES-GCM with iv is supported' , ( ) => {
12+ expect (
13+ Subtle . supports ( 'encrypt' , {
14+ name : 'AES-GCM' ,
15+ iv : new Uint8Array ( 12 ) ,
16+ } ) ,
17+ ) . to . equal ( true ) ;
18+ } ) ;
19+
20+ test ( SUITE , 'encrypt: AES-GCM without iv is not supported' , ( ) => {
21+ expect ( Subtle . supports ( 'encrypt' , 'AES-GCM' ) ) . to . equal ( false ) ;
22+ } ) ;
23+
24+ test ( SUITE , 'encrypt: AES-CBC with invalid iv length is not supported' , ( ) => {
25+ expect (
26+ Subtle . supports ( 'encrypt' , {
27+ name : 'AES-CBC' ,
28+ iv : new Uint8Array ( 12 ) ,
29+ } ) ,
30+ ) . to . equal ( false ) ;
31+ } ) ;
32+
33+ test ( SUITE , 'encrypt: AES-GCM with invalid tagLength is not supported' , ( ) => {
34+ expect (
35+ Subtle . supports ( 'encrypt' , {
36+ name : 'AES-GCM' ,
37+ iv : new Uint8Array ( 12 ) ,
38+ tagLength : 24 ,
39+ } ) ,
40+ ) . to . equal ( false ) ;
1041} ) ;
1142
1243test ( SUITE , 'encrypt: RSA-OAEP is supported' , ( ) => {
1344 expect ( Subtle . supports ( 'encrypt' , 'RSA-OAEP' ) ) . to . equal ( true ) ;
1445} ) ;
1546
16- test ( SUITE , 'encrypt: ChaCha20-Poly1305 is supported' , ( ) => {
17- expect ( Subtle . supports ( 'encrypt' , 'ChaCha20-Poly1305' ) ) . to . equal ( true ) ;
47+ test ( SUITE , 'encrypt: ChaCha20-Poly1305 with iv is supported' , ( ) => {
48+ expect (
49+ Subtle . supports ( 'encrypt' , {
50+ name : 'ChaCha20-Poly1305' ,
51+ iv : new Uint8Array ( 12 ) ,
52+ } ) ,
53+ ) . to . equal ( true ) ;
1854} ) ;
1955
2056test ( SUITE , 'encrypt: HMAC is not supported' , ( ) => {
@@ -30,8 +66,21 @@ test(SUITE, 'sign: Ed25519 is supported', () => {
3066 expect ( Subtle . supports ( 'sign' , 'Ed25519' ) ) . to . equal ( true ) ;
3167} ) ;
3268
33- test ( SUITE , 'sign: ECDSA is supported' , ( ) => {
34- expect ( Subtle . supports ( 'sign' , 'ECDSA' ) ) . to . equal ( true ) ;
69+ // EcdsaParams.hash is required under strict normalization (#1025).
70+ test ( SUITE , 'sign: ECDSA with hash is supported' , ( ) => {
71+ expect ( Subtle . supports ( 'sign' , { name : 'ECDSA' , hash : 'SHA-256' } ) ) . to . equal (
72+ true ,
73+ ) ;
74+ } ) ;
75+
76+ test ( SUITE , 'sign: ECDSA without hash is not supported' , ( ) => {
77+ expect ( Subtle . supports ( 'sign' , 'ECDSA' ) ) . to . equal ( false ) ;
78+ } ) ;
79+
80+ test ( SUITE , 'sign: ECDSA with non-SHA hash is not supported' , ( ) => {
81+ expect ( Subtle . supports ( 'sign' , { name : 'ECDSA' , hash : 'MD5' } ) ) . to . equal (
82+ false ,
83+ ) ;
3584} ) ;
3685
3786test ( SUITE , 'sign: HMAC is supported' , ( ) => {
@@ -55,6 +104,33 @@ test(SUITE, 'digest: SHA-512 is supported', () => {
55104 expect ( Subtle . supports ( 'digest' , 'SHA-512' ) ) . to . equal ( true ) ;
56105} ) ;
57106
107+ test (
108+ SUITE ,
109+ 'digest: TurboSHAKE128 invalid outputLength is not supported' ,
110+ ( ) => {
111+ expect (
112+ Subtle . supports ( 'digest' , {
113+ name : 'TurboSHAKE128' ,
114+ outputLength : 0 ,
115+ } ) ,
116+ ) . to . equal ( false ) ;
117+ } ,
118+ ) ;
119+
120+ test (
121+ SUITE ,
122+ 'digest: TurboSHAKE128 invalid domainSeparation is not supported' ,
123+ ( ) => {
124+ expect (
125+ Subtle . supports ( 'digest' , {
126+ name : 'TurboSHAKE128' ,
127+ outputLength : 256 ,
128+ domainSeparation : 0x80 ,
129+ } ) ,
130+ ) . to . equal ( false ) ;
131+ } ,
132+ ) ;
133+
58134// --- GenerateKey ---
59135test ( SUITE , 'generateKey: Ed25519 is supported' , ( ) => {
60136 expect ( Subtle . supports ( 'generateKey' , 'Ed25519' ) ) . to . equal ( true ) ;
@@ -70,20 +146,54 @@ test(SUITE, 'generateKey: HKDF is not supported', () => {
70146
71147// --- DeriveBits ---
72148// HKDF/PBKDF2/Argon2 require an explicit length per Node webcrypto.js:1689-1714.
73- test ( SUITE , 'deriveBits: HKDF with length is supported' , ( ) => {
74- expect ( Subtle . supports ( 'deriveBits' , 'HKDF' , 256 ) ) . to . equal ( true ) ;
149+ // Under strict normalization (#1025) the dictionary members are also required.
150+ const HKDF_FULL : SubtleAlgorithm = {
151+ name : 'HKDF' ,
152+ hash : 'SHA-256' ,
153+ salt : new Uint8Array ( 0 ) ,
154+ info : new Uint8Array ( 0 ) ,
155+ } ;
156+ const PBKDF2_FULL : SubtleAlgorithm = {
157+ name : 'PBKDF2' ,
158+ hash : 'SHA-256' ,
159+ salt : new Uint8Array ( 8 ) ,
160+ iterations : 1000 ,
161+ } ;
162+
163+ test ( SUITE , 'deriveBits: HKDF with full params + length is supported' , ( ) => {
164+ expect ( Subtle . supports ( 'deriveBits' , HKDF_FULL , 256 ) ) . to . equal ( true ) ;
75165} ) ;
76166
77- test ( SUITE , 'deriveBits: PBKDF2 with length is supported' , ( ) => {
78- expect ( Subtle . supports ( 'deriveBits' , 'PBKDF2' , 256 ) ) . to . equal ( true ) ;
167+ test ( SUITE , 'deriveBits: PBKDF2 with full params + length is supported' , ( ) => {
168+ expect ( Subtle . supports ( 'deriveBits' , PBKDF2_FULL , 256 ) ) . to . equal ( true ) ;
169+ } ) ;
170+
171+ test ( SUITE , 'deriveBits: PBKDF2 with zero iterations is not supported' , ( ) => {
172+ expect (
173+ Subtle . supports (
174+ 'deriveBits' ,
175+ {
176+ ...PBKDF2_FULL ,
177+ iterations : 0 ,
178+ } ,
179+ 256 ,
180+ ) ,
181+ ) . to . equal ( false ) ;
182+ } ) ;
183+
184+ test ( SUITE , 'deriveBits: HKDF missing salt/info is not supported' , ( ) => {
185+ expect ( Subtle . supports ( 'deriveBits' , 'HKDF' , 256 ) ) . to . equal ( false ) ;
79186} ) ;
80187
81188test ( SUITE , 'deriveBits: HKDF without length is not supported' , ( ) => {
82- expect ( Subtle . supports ( 'deriveBits' , 'HKDF' ) ) . to . equal ( false ) ;
189+ expect ( Subtle . supports ( 'deriveBits' , HKDF_FULL ) ) . to . equal ( false ) ;
83190} ) ;
84191
85- test ( SUITE , 'deriveBits: X25519 is supported' , ( ) => {
86- expect ( Subtle . supports ( 'deriveBits' , 'X25519' ) ) . to . equal ( true ) ;
192+ // EcdhKeyDeriveParams.public (a CryptoKey) is required, so calling
193+ // supports('deriveBits', 'X25519') without it returns false under strict
194+ // normalization — mirrors Node's behavior.
195+ test ( SUITE , 'deriveBits: X25519 without public key is not supported' , ( ) => {
196+ expect ( Subtle . supports ( 'deriveBits' , 'X25519' ) ) . to . equal ( false ) ;
87197} ) ;
88198
89199test ( SUITE , 'deriveBits: AES-GCM is not supported' , ( ) => {
@@ -93,20 +203,23 @@ test(SUITE, 'deriveBits: AES-GCM is not supported', () => {
93203// --- DeriveKey ---
94204test ( SUITE , 'deriveKey: HKDF + AES-GCM with length 256 is supported' , ( ) => {
95205 expect (
96- Subtle . supports ( 'deriveKey' , 'HKDF' , { name : 'AES-GCM' , length : 256 } ) ,
206+ Subtle . supports ( 'deriveKey' , HKDF_FULL , {
207+ name : 'AES-GCM' ,
208+ length : 256 ,
209+ } ) ,
97210 ) . to . equal ( true ) ;
98211} ) ;
99212
100213// AES key length is required for getKeyLength — Node webcrypto.js:269-279.
101214test ( SUITE , 'deriveKey: HKDF + AES-GCM without length is not supported' , ( ) => {
102- expect ( Subtle . supports ( 'deriveKey' , 'HKDF' , 'AES-GCM' ) ) . to . equal ( false ) ;
215+ expect ( Subtle . supports ( 'deriveKey' , HKDF_FULL , 'AES-GCM' ) ) . to . equal ( false ) ;
103216} ) ;
104217
105218test (
106219 SUITE ,
107220 'deriveKey: HKDF without additional algorithm returns false' ,
108221 ( ) => {
109- expect ( Subtle . supports ( 'deriveKey' , 'HKDF' ) ) . to . equal ( false ) ;
222+ expect ( Subtle . supports ( 'deriveKey' , HKDF_FULL ) ) . to . equal ( false ) ;
110223 } ,
111224) ;
112225
@@ -176,24 +289,30 @@ test(SUITE, 'encapsulateKey: ML-KEM-768 + Ed25519 is not supported', () => {
176289 ) ;
177290} ) ;
178291
292+ // Under strict normalization (#1025), HmacImportParams.hash is required.
179293test (
180294 SUITE ,
181- 'encapsulateKey: ML-KEM-768 + HMAC default length supported' ,
295+ 'encapsulateKey: ML-KEM-768 + HMAC without hash is not supported' ,
182296 ( ) => {
183297 expect ( Subtle . supports ( 'encapsulateKey' , 'ML-KEM-768' , 'HMAC' ) ) . to . equal (
184- true ,
298+ false ,
185299 ) ;
186300 } ,
187301) ;
188302
189- test ( SUITE , 'encapsulateKey: ML-KEM-768 + HMAC length 256 supported' , ( ) => {
190- expect (
191- Subtle . supports ( 'encapsulateKey' , 'ML-KEM-768' , {
192- name : 'HMAC' ,
193- length : 256 ,
194- } ) ,
195- ) . to . equal ( true ) ;
196- } ) ;
303+ test (
304+ SUITE ,
305+ 'encapsulateKey: ML-KEM-768 + HMAC with hash + length 256 supported' ,
306+ ( ) => {
307+ expect (
308+ Subtle . supports ( 'encapsulateKey' , 'ML-KEM-768' , {
309+ name : 'HMAC' ,
310+ hash : 'SHA-256' ,
311+ length : 256 ,
312+ } ) ,
313+ ) . to . equal ( true ) ;
314+ } ,
315+ ) ;
197316
198317test (
199318 SUITE ,
@@ -202,6 +321,7 @@ test(
202321 expect (
203322 Subtle . supports ( 'encapsulateKey' , 'ML-KEM-768' , {
204323 name : 'HMAC' ,
324+ hash : 'SHA-256' ,
205325 length : 512 ,
206326 } ) ,
207327 ) . to . equal ( false ) ;
@@ -210,19 +330,33 @@ test(
210330
211331// --- DeriveBits per-algorithm length validators ---
212332test ( SUITE , 'deriveBits: HKDF with non-multiple-of-8 length rejected' , ( ) => {
213- expect ( Subtle . supports ( 'deriveBits' , 'HKDF' , 257 ) ) . to . equal ( false ) ;
333+ expect ( Subtle . supports ( 'deriveBits' , HKDF_FULL , 257 ) ) . to . equal ( false ) ;
214334} ) ;
215335
216336test ( SUITE , 'deriveBits: PBKDF2 with non-multiple-of-8 length rejected' , ( ) => {
217- expect ( Subtle . supports ( 'deriveBits' , 'PBKDF2' , 257 ) ) . to . equal ( false ) ;
337+ expect ( Subtle . supports ( 'deriveBits' , PBKDF2_FULL , 257 ) ) . to . equal ( false ) ;
218338} ) ;
219339
340+ const ARGON2_FULL : SubtleAlgorithm = {
341+ name : 'Argon2id' ,
342+ nonce : new Uint8Array ( 16 ) ,
343+ parallelism : 1 ,
344+ memory : 8 ,
345+ passes : 2 ,
346+ } ;
347+
220348test ( SUITE , 'deriveBits: Argon2id length below 32 rejected' , ( ) => {
221- expect ( Subtle . supports ( 'deriveBits' , 'Argon2id' , 16 ) ) . to . equal ( false ) ;
349+ expect ( Subtle . supports ( 'deriveBits' , ARGON2_FULL , 16 ) ) . to . equal ( false ) ;
222350} ) ;
223351
224352test ( SUITE , 'deriveBits: Argon2id length 32 supported' , ( ) => {
225- expect ( Subtle . supports ( 'deriveBits' , 'Argon2id' , 32 ) ) . to . equal ( true ) ;
353+ expect ( Subtle . supports ( 'deriveBits' , ARGON2_FULL , 32 ) ) . to . equal ( true ) ;
354+ } ) ;
355+
356+ // New: regression for #1025 — strict normalization rejects missing required
357+ // dictionary members during deriveBits length validation.
358+ test ( SUITE , 'deriveBits: Argon2id missing required members rejected' , ( ) => {
359+ expect ( Subtle . supports ( 'deriveBits' , 'Argon2id' , 32 ) ) . to . equal ( false ) ;
226360} ) ;
227361
228362// --- Invalid operation ---
0 commit comments