xref: /expo/apps/test-suite/tests/Crypto.js (revision 6aedc028)
1import * as Crypto from 'expo-crypto';
2import { Platform } from 'react-native';
3
4function areArrayBuffersEqual(a, b) {
5  if (a.byteLength !== b.byteLength) {
6    return false;
7  }
8  const dv1 = new Int8Array(a);
9  const dv2 = new Int8Array(b);
10  return dv1.every((item, index) => item === dv2[index]);
11}
12
13function getArrayBufferFromHex(hex) {
14  const bytes = new Uint8Array(Math.ceil(hex.length / 2));
15  return bytes.map((_, index) => parseInt(hex.substr(index * 2, 2), 16)).buffer;
16}
17
18const { CryptoEncoding, CryptoDigestAlgorithm } = Crypto;
19
20const testValue = 'Expo';
21const testTypedArray = new Uint8Array([69, 120, 112, 111]);
22
23const valueMapping = {
24  [CryptoEncoding.HEX]: {
25    [CryptoDigestAlgorithm.SHA1]: `c275355dc46ac171633935033d113e3872d595e5`,
26    [CryptoDigestAlgorithm.SHA256]: `f5e5cae536b49d394e1e72d4368d64b00a23298ec5ae11f3a9102a540e2532dc`,
27    [CryptoDigestAlgorithm.SHA384]: `aa356c88afdbd8a7a5a9c3133541af0035e4b04e82438a223aa1939240ccb6b3ca28294b5ac0f42703b15183f4c016fc`,
28    [CryptoDigestAlgorithm.SHA512]: `f1924f3e61aac4e4caa7fd566591b8abb541b0e642cd7bf0c71573267cfacf1b6dafe905bd6e42633bfba67c59774e070095e19a7c2078ac18ccd23245d76f1c`,
29    [CryptoDigestAlgorithm.MD2]: `fb85323c3b15b016e0351006e2f47bf7`,
30    [CryptoDigestAlgorithm.MD4]: `2d36099794ec182cbb36d02e1188fc1e`,
31    [CryptoDigestAlgorithm.MD5]: `c29f23f279126757ba18ec74d0d27cfa`,
32  },
33  [CryptoEncoding.BASE64]: {
34    [CryptoDigestAlgorithm.SHA1]: `wnU1XcRqwXFjOTUDPRE+OHLVleU=`,
35    [CryptoDigestAlgorithm.SHA256]: `9eXK5Ta0nTlOHnLUNo1ksAojKY7FrhHzqRAqVA4lMtw=`,
36    [CryptoDigestAlgorithm.SHA384]: `qjVsiK/b2KelqcMTNUGvADXksE6CQ4oiOqGTkkDMtrPKKClLWsD0JwOxUYP0wBb8`,
37    [CryptoDigestAlgorithm.SHA512]: `8ZJPPmGqxOTKp/1WZZG4q7VBsOZCzXvwxxVzJnz6zxttr+kFvW5CYzv7pnxZd04HAJXhmnwgeKwYzNIyRddvHA==`,
38    [CryptoDigestAlgorithm.MD2]: `+4UyPDsVsBbgNRAG4vR79w==`,
39    [CryptoDigestAlgorithm.MD4]: `LTYJl5TsGCy7NtAuEYj8Hg==`,
40    [CryptoDigestAlgorithm.MD5]: `wp8j8nkSZ1e6GOx00NJ8+g==`,
41  },
42};
43
44export const name = 'Crypto';
45
46const UNSUPPORTED = Platform.select({
47  web: ['MD2', 'MD4', 'MD5'],
48  android: ['MD2', 'MD4'],
49  default: [],
50});
51function supportedAlgorithm(algorithm) {
52  return !UNSUPPORTED.includes(algorithm);
53}
54
55export async function test({ describe, it, expect }) {
56  describe('Crypto', () => {
57    describe('digestStringAsync()', async () => {
58      it(`Invalid CryptoEncoding throws an error`, async () => {
59        let error = null;
60        try {
61          await Crypto.digestStringAsync(CryptoDigestAlgorithm.SHA1, testValue, {
62            encoding: 'INVALID',
63          });
64        } catch (e) {
65          error = e;
66        }
67        expect(error).not.toBeNull();
68      });
69
70      for (const encodingEntry of Object.entries(CryptoEncoding)) {
71        const [encodingKey, encoding] = encodingEntry;
72        describe(`Encoded with CryptoEncoding.${encodingKey}`, () => {
73          for (const entry of Object.entries(CryptoDigestAlgorithm)) {
74            const [key, algorithm] = entry;
75            it(`CryptoDigestAlgorithm.${key}`, async () => {
76              const targetValue = valueMapping[encoding][algorithm];
77              if (supportedAlgorithm(algorithm)) {
78                const value = await Crypto.digestStringAsync(algorithm, testValue, { encoding });
79                expect(value).toBe(targetValue);
80              } else {
81                let error = null;
82                try {
83                  await Crypto.digestStringAsync(algorithm, testValue, { encoding });
84                } catch (e) {
85                  error = e;
86                }
87                expect(error).not.toBeNull();
88              }
89            });
90          }
91        });
92      }
93    });
94
95    describe('digest()', async () => {
96      for (const entry of Object.entries(CryptoDigestAlgorithm)) {
97        const [key, algorithm] = entry;
98        it(`CryptoDigestAlgorithm.${key}`, async () => {
99          const hex = valueMapping[CryptoEncoding.HEX][algorithm];
100          const targetValue = getArrayBufferFromHex(hex);
101          if (supportedAlgorithm(algorithm)) {
102            const value = await Crypto.digest(algorithm, testTypedArray);
103            const buffersAreEqual = areArrayBuffersEqual(value, targetValue);
104            expect(buffersAreEqual).toBe(true);
105          }
106        });
107      }
108    });
109  });
110}
111