|
2 | 2 | Buffer, |
3 | 3 | getCiphers, |
4 | 4 | createCipheriv, |
| 5 | + createDecipheriv, |
5 | 6 | randomFillSync, |
6 | 7 | } from 'react-native-quick-crypto'; |
7 | 8 | import { expect } from 'chai'; |
@@ -133,3 +134,77 @@ test(SUITE, 'GCM getAuthTag', () => { |
133 | 134 | const tag = cipher.getAuthTag(); |
134 | 135 | expect(tag.length).to.equal(16); |
135 | 136 | }); |
| 137 | + |
| 138 | +// Issue #798: decipher.final() should throw on incorrect key for aes-256-gcm |
| 139 | +test(SUITE, 'GCM wrong key throws error (issue #798)', () => { |
| 140 | + const correctKey = Buffer.from('a'.repeat(64), 'hex'); // 32 bytes |
| 141 | + const wrongKey = Buffer.from('b'.repeat(64), 'hex'); // different 32 bytes |
| 142 | + const testIv = randomFillSync(new Uint8Array(12)); |
| 143 | + const testPlaintext = Buffer.from('test data for encryption'); |
| 144 | + const testAad = Buffer.from('additional data'); |
| 145 | + |
| 146 | + // Encrypt with correct key |
| 147 | + const cipher = createCipheriv('aes-256-gcm', correctKey, Buffer.from(testIv)); |
| 148 | + cipher.setAAD(testAad); |
| 149 | + const encrypted = Buffer.concat([ |
| 150 | + cipher.update(testPlaintext), |
| 151 | + cipher.final(), |
| 152 | + ]); |
| 153 | + const authTag = cipher.getAuthTag(); |
| 154 | + |
| 155 | + // Decrypt with wrong key - should throw on final() |
| 156 | + const decipher = createDecipheriv( |
| 157 | + 'aes-256-gcm', |
| 158 | + wrongKey, |
| 159 | + Buffer.from(testIv), |
| 160 | + ); |
| 161 | + decipher.setAAD(testAad); |
| 162 | + decipher.setAuthTag(authTag); |
| 163 | + decipher.update(encrypted); |
| 164 | + |
| 165 | + expect(() => decipher.final()).to.throw(); |
| 166 | +}); |
| 167 | + |
| 168 | +test(SUITE, 'GCM tampered ciphertext throws error', () => { |
| 169 | + const testKey = Buffer.from(randomFillSync(new Uint8Array(32))); |
| 170 | + const testIv = Buffer.from(randomFillSync(new Uint8Array(12))); |
| 171 | + const testPlaintext = Buffer.from('test data'); |
| 172 | + |
| 173 | + const cipher = createCipheriv('aes-256-gcm', testKey, testIv); |
| 174 | + const encrypted = Buffer.concat([ |
| 175 | + cipher.update(testPlaintext), |
| 176 | + cipher.final(), |
| 177 | + ]); |
| 178 | + const authTag = cipher.getAuthTag(); |
| 179 | + |
| 180 | + // Tamper with ciphertext |
| 181 | + encrypted[0] = encrypted[0]! ^ 1; |
| 182 | + |
| 183 | + const decipher = createDecipheriv('aes-256-gcm', testKey, testIv); |
| 184 | + decipher.setAuthTag(authTag); |
| 185 | + decipher.update(encrypted); |
| 186 | + |
| 187 | + expect(() => decipher.final()).to.throw(); |
| 188 | +}); |
| 189 | + |
| 190 | +test(SUITE, 'GCM tampered auth tag throws error', () => { |
| 191 | + const testKey = Buffer.from(randomFillSync(new Uint8Array(32))); |
| 192 | + const testIv = Buffer.from(randomFillSync(new Uint8Array(12))); |
| 193 | + const testPlaintext = Buffer.from('test data'); |
| 194 | + |
| 195 | + const cipher = createCipheriv('aes-256-gcm', testKey, testIv); |
| 196 | + const encrypted = Buffer.concat([ |
| 197 | + cipher.update(testPlaintext), |
| 198 | + cipher.final(), |
| 199 | + ]); |
| 200 | + const authTag = cipher.getAuthTag(); |
| 201 | + |
| 202 | + // Tamper with auth tag |
| 203 | + authTag[0] = authTag[0]! ^ 1; |
| 204 | + |
| 205 | + const decipher = createDecipheriv('aes-256-gcm', testKey, testIv); |
| 206 | + decipher.setAuthTag(authTag); |
| 207 | + decipher.update(encrypted); |
| 208 | + |
| 209 | + expect(() => decipher.final()).to.throw(); |
| 210 | +}); |
0 commit comments