|  |  |  | /* global Signal, textsecure, libsignal */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe('Crypto', () => { | 
					
						
							|  |  |  |   describe('accessKey/profileKey', () => { | 
					
						
							|  |  |  |     it('verification roundtrips', async () => { | 
					
						
							|  |  |  |       const profileKey = await Signal.Crypto.getRandomBytes(32); | 
					
						
							|  |  |  |       const accessKey = await Signal.Crypto.deriveAccessKey(profileKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const verifier = await Signal.Crypto.getAccessKeyVerifier(accessKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const correct = await Signal.Crypto.verifyAccessKey(accessKey, verifier); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       assert.strictEqual(correct, true); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('symmetric encryption', () => { | 
					
						
							|  |  |  |     it('roundtrips', async () => { | 
					
						
							|  |  |  |       const message = 'this is my message'; | 
					
						
							|  |  |  |       const plaintext = dcodeIO.ByteBuffer.wrap( | 
					
						
							|  |  |  |         message, | 
					
						
							|  |  |  |         'binary' | 
					
						
							|  |  |  |       ).toArrayBuffer(); | 
					
						
							|  |  |  |       const key = textsecure.crypto.getRandomBytes(32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); | 
					
						
							|  |  |  |       const decrypted = await Signal.Crypto.decryptSymmetric(key, encrypted); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const equal = Signal.Crypto.constantTimeEqual(plaintext, decrypted); | 
					
						
							|  |  |  |       if (!equal) { | 
					
						
							|  |  |  |         throw new Error('The output and input did not match!'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('roundtrip fails if nonce is modified', async () => { | 
					
						
							|  |  |  |       const message = 'this is my message'; | 
					
						
							|  |  |  |       const plaintext = dcodeIO.ByteBuffer.wrap( | 
					
						
							|  |  |  |         message, | 
					
						
							|  |  |  |         'binary' | 
					
						
							|  |  |  |       ).toArrayBuffer(); | 
					
						
							|  |  |  |       const key = textsecure.crypto.getRandomBytes(32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); | 
					
						
							|  |  |  |       const uintArray = new Uint8Array(encrypted); | 
					
						
							|  |  |  |       uintArray[2] += 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         assert.strictEqual( | 
					
						
							|  |  |  |           error.message, | 
					
						
							|  |  |  |           'decryptSymmetric: Failed to decrypt; MAC verification failed' | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       throw new Error('Expected error to be thrown'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('roundtrip fails if mac is modified', async () => { | 
					
						
							|  |  |  |       const message = 'this is my message'; | 
					
						
							|  |  |  |       const plaintext = dcodeIO.ByteBuffer.wrap( | 
					
						
							|  |  |  |         message, | 
					
						
							|  |  |  |         'binary' | 
					
						
							|  |  |  |       ).toArrayBuffer(); | 
					
						
							|  |  |  |       const key = textsecure.crypto.getRandomBytes(32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); | 
					
						
							|  |  |  |       const uintArray = new Uint8Array(encrypted); | 
					
						
							|  |  |  |       uintArray[uintArray.length - 3] += 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         assert.strictEqual( | 
					
						
							|  |  |  |           error.message, | 
					
						
							|  |  |  |           'decryptSymmetric: Failed to decrypt; MAC verification failed' | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       throw new Error('Expected error to be thrown'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('roundtrip fails if encrypted contents are modified', async () => { | 
					
						
							|  |  |  |       const message = 'this is my message'; | 
					
						
							|  |  |  |       const plaintext = dcodeIO.ByteBuffer.wrap( | 
					
						
							|  |  |  |         message, | 
					
						
							|  |  |  |         'binary' | 
					
						
							|  |  |  |       ).toArrayBuffer(); | 
					
						
							|  |  |  |       const key = textsecure.crypto.getRandomBytes(32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); | 
					
						
							|  |  |  |       const uintArray = new Uint8Array(encrypted); | 
					
						
							|  |  |  |       uintArray[35] += 9; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         assert.strictEqual( | 
					
						
							|  |  |  |           error.message, | 
					
						
							|  |  |  |           'decryptSymmetric: Failed to decrypt; MAC verification failed' | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       throw new Error('Expected error to be thrown'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('encrypted device name', () => { | 
					
						
							|  |  |  |     it('roundtrips', async () => { | 
					
						
							|  |  |  |       const deviceName = 'v1.19.0 on Windows 10'; | 
					
						
							|  |  |  |       const identityKey = await libsignal.KeyHelper.generateIdentityKeyPair(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const encrypted = await Signal.Crypto.encryptDeviceName( | 
					
						
							|  |  |  |         deviceName, | 
					
						
							|  |  |  |         identityKey.pubKey | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |       const decrypted = await Signal.Crypto.decryptDeviceName( | 
					
						
							|  |  |  |         encrypted, | 
					
						
							|  |  |  |         identityKey.privKey | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       assert.strictEqual(decrypted, deviceName); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('fails if iv is changed', async () => { | 
					
						
							|  |  |  |       const deviceName = 'v1.19.0 on Windows 10'; | 
					
						
							|  |  |  |       const identityKey = await libsignal.KeyHelper.generateIdentityKeyPair(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const encrypted = await Signal.Crypto.encryptDeviceName( | 
					
						
							|  |  |  |         deviceName, | 
					
						
							|  |  |  |         identityKey.pubKey | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |       encrypted.syntheticIv = Signal.Crypto.getRandomBytes(16); | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         await Signal.Crypto.decryptDeviceName(encrypted, identityKey.privKey); | 
					
						
							|  |  |  |       } catch (error) { | 
					
						
							|  |  |  |         assert.strictEqual( | 
					
						
							|  |  |  |           error.message, | 
					
						
							|  |  |  |           'decryptDeviceName: synthetic IV did not match' | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('attachment encryption', () => { | 
					
						
							|  |  |  |     it('roundtrips', async () => { | 
					
						
							|  |  |  |       const staticKeyPair = await libsignal.KeyHelper.generateIdentityKeyPair(); | 
					
						
							|  |  |  |       const message = 'this is my message'; | 
					
						
							|  |  |  |       const plaintext = Signal.Crypto.bytesFromString(message); | 
					
						
							|  |  |  |       const path = | 
					
						
							|  |  |  |         'fa/facdf99c22945b1c9393345599a276f4b36ad7ccdc8c2467f5441b742c2d11fa'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const encrypted = await Signal.Crypto.encryptAttachment( | 
					
						
							|  |  |  |         staticKeyPair.pubKey.slice(1), | 
					
						
							|  |  |  |         path, | 
					
						
							|  |  |  |         plaintext | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |       const decrypted = await Signal.Crypto.decryptAttachment( | 
					
						
							|  |  |  |         staticKeyPair.privKey, | 
					
						
							|  |  |  |         path, | 
					
						
							|  |  |  |         encrypted | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const equal = Signal.Crypto.constantTimeEqual(plaintext, decrypted); | 
					
						
							|  |  |  |       if (!equal) { | 
					
						
							|  |  |  |         throw new Error('The output and input did not match!'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); |