expo-crypto 15.0.9-canary-20260105-6b962e6 → 15.1.0-canary-20260113-0ce2b9c
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/CHANGELOG.md +2 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/crypto/aes/AesConfig.kt +9 -0
- package/android/src/main/java/expo/modules/crypto/aes/AesCryptoModule.kt +169 -0
- package/android/src/main/java/expo/modules/crypto/aes/AesExceptions.kt +18 -0
- package/android/src/main/java/expo/modules/crypto/aes/enums/DataFormat.kt +8 -0
- package/android/src/main/java/expo/modules/crypto/aes/enums/KeyEncoding.kt +8 -0
- package/android/src/main/java/expo/modules/crypto/aes/enums/KeySize.kt +19 -0
- package/android/src/main/java/expo/modules/crypto/aes/extensions/ByteArrayExtensions.kt +31 -0
- package/android/src/main/java/expo/modules/crypto/aes/extensions/CipherExtensions.kt +24 -0
- package/android/src/main/java/expo/modules/crypto/aes/objects/EncryptionKey.kt +32 -0
- package/android/src/main/java/expo/modules/crypto/aes/objects/SealedData.kt +79 -0
- package/android/src/main/java/expo/modules/crypto/aes/records/CiphertextOptions.kt +10 -0
- package/android/src/main/java/expo/modules/crypto/aes/records/DecryptOptions.kt +16 -0
- package/android/src/main/java/expo/modules/crypto/aes/records/EncryptOptions.kt +44 -0
- package/android/src/main/java/expo/modules/crypto/aes/records/SealedDataConfig.kt +11 -0
- package/build/Crypto.d.ts +1 -0
- package/build/Crypto.d.ts.map +1 -1
- package/build/Crypto.js +1 -0
- package/build/Crypto.js.map +1 -1
- package/build/aes/ExpoCryptoAES.d.ts +123 -0
- package/build/aes/ExpoCryptoAES.d.ts.map +1 -0
- package/build/aes/ExpoCryptoAES.js +4 -0
- package/build/aes/ExpoCryptoAES.js.map +1 -0
- package/build/aes/ExpoCryptoAES.web.d.ts +41 -0
- package/build/aes/ExpoCryptoAES.web.d.ts.map +1 -0
- package/build/aes/ExpoCryptoAES.web.js +166 -0
- package/build/aes/ExpoCryptoAES.web.js.map +1 -0
- package/build/aes/aes.types.d.ts +115 -0
- package/build/aes/aes.types.d.ts.map +1 -0
- package/build/aes/aes.types.js +16 -0
- package/build/aes/aes.types.js.map +1 -0
- package/build/aes/index.d.ts +59 -0
- package/build/aes/index.d.ts.map +1 -0
- package/build/aes/index.js +73 -0
- package/build/aes/index.js.map +1 -0
- package/build/aes/web-utils.d.ts +7 -0
- package/build/aes/web-utils.d.ts.map +1 -0
- package/build/aes/web-utils.js +49 -0
- package/build/aes/web-utils.js.map +1 -0
- package/expo-module.config.json +3 -3
- package/ios/AES/AesCryptoModule.swift +212 -0
- package/ios/AES/EncryptionKey.swift +76 -0
- package/ios/AES/Exceptions.swift +32 -0
- package/ios/AES/SealedData.swift +80 -0
- package/ios/AES/Utilities.swift +52 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c-sources.jar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c-sources.jar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c-sources.jar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c-sources.jar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c-sources.jar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.aar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.aar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.aar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.aar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.module +87 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.module.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.module.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.module.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.module.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/{15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.pom → 15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.pom} +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.pom.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.pom.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.pom.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.1.0-canary-20260113-0ce2b9c/expo.modules.crypto-15.1.0-canary-20260113-0ce2b9c.pom.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/maven-metadata.xml +4 -4
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/maven-metadata.xml.sha512 +1 -1
- package/mocks/ExpoCryptoAES.ts +34 -0
- package/package.json +3 -3
- package/src/Crypto.ts +1 -0
- package/src/aes/ExpoCryptoAES.ts +147 -0
- package/src/aes/ExpoCryptoAES.web.ts +249 -0
- package/src/aes/aes.types.ts +126 -0
- package/src/aes/index.ts +150 -0
- package/src/aes/web-utils.ts +58 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6-sources.jar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6-sources.jar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6-sources.jar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6-sources.jar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6-sources.jar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.aar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.aar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.aar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.aar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.module +0 -87
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.module.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.module.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.module.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.module.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.pom.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.pom.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.pom.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.crypto/15.0.9-canary-20260105-6b962e6/expo.modules.crypto-15.0.9-canary-20260105-6b962e6.pom.sha512 +0 -1
package/CHANGELOG.md
CHANGED
package/android/build.gradle
CHANGED
|
@@ -4,13 +4,13 @@ plugins {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
group = 'host.exp.exponent'
|
|
7
|
-
version = '15.0
|
|
7
|
+
version = '15.1.0-canary-20260113-0ce2b9c'
|
|
8
8
|
|
|
9
9
|
android {
|
|
10
10
|
namespace "expo.modules.crypto"
|
|
11
11
|
defaultConfig {
|
|
12
12
|
versionCode 25
|
|
13
|
-
versionName "15.0
|
|
13
|
+
versionName "15.1.0-canary-20260113-0ce2b9c"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
package expo.modules.crypto.aes
|
|
2
|
+
|
|
3
|
+
import android.util.Base64
|
|
4
|
+
import expo.modules.crypto.aes.AesConfig.CIPHER_TRANSFORMATION_NAME
|
|
5
|
+
import expo.modules.crypto.aes.AesConfig.DEFAULT_TAG_SIZE
|
|
6
|
+
import expo.modules.crypto.aes.enums.DataFormat
|
|
7
|
+
import expo.modules.crypto.aes.enums.KeyEncoding
|
|
8
|
+
import expo.modules.crypto.aes.enums.KeySize
|
|
9
|
+
import expo.modules.crypto.aes.extensions.decrypt
|
|
10
|
+
import expo.modules.crypto.aes.extensions.encoded
|
|
11
|
+
import expo.modules.crypto.aes.extensions.encrypt
|
|
12
|
+
import expo.modules.crypto.aes.extensions.formatted
|
|
13
|
+
import expo.modules.crypto.aes.objects.EncryptionKey
|
|
14
|
+
import expo.modules.crypto.aes.objects.SealedData
|
|
15
|
+
import expo.modules.crypto.aes.records.CiphertextOptions
|
|
16
|
+
import expo.modules.crypto.aes.records.DecryptOptions
|
|
17
|
+
import expo.modules.crypto.aes.records.EncryptOptions
|
|
18
|
+
import expo.modules.crypto.aes.records.SealedDataConfig
|
|
19
|
+
import expo.modules.kotlin.apifeatures.EitherType
|
|
20
|
+
import expo.modules.kotlin.exception.Exceptions
|
|
21
|
+
import expo.modules.kotlin.modules.Module
|
|
22
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
23
|
+
import expo.modules.kotlin.types.Either
|
|
24
|
+
import java.nio.ByteBuffer
|
|
25
|
+
import java.security.SecureRandom
|
|
26
|
+
import javax.crypto.Cipher
|
|
27
|
+
import javax.crypto.spec.GCMParameterSpec
|
|
28
|
+
|
|
29
|
+
@OptIn(EitherType::class)
|
|
30
|
+
typealias BinaryInput = Either<ByteArray, String>
|
|
31
|
+
|
|
32
|
+
@OptIn(EitherType::class, ExperimentalStdlibApi::class)
|
|
33
|
+
class AesCryptoModule : Module() {
|
|
34
|
+
private val rng: SecureRandom by lazy { SecureRandom() }
|
|
35
|
+
|
|
36
|
+
override fun definition() = ModuleDefinition {
|
|
37
|
+
Name("ExpoCryptoAES")
|
|
38
|
+
|
|
39
|
+
AsyncFunction("encryptAsync", this@AesCryptoModule::encrypt)
|
|
40
|
+
AsyncFunction("decryptAsync", this@AesCryptoModule::decrypt)
|
|
41
|
+
|
|
42
|
+
Class("EncryptionKey", EncryptionKey::class) {
|
|
43
|
+
Constructor {
|
|
44
|
+
throw Exceptions.IllegalArgument("EncryptionKey constructor cannot be used directly")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
StaticAsyncFunction("generate") { size: KeySize? ->
|
|
48
|
+
EncryptionKey(size ?: KeySize.AES256)
|
|
49
|
+
}
|
|
50
|
+
StaticAsyncFunction("import") { input: Either<ByteArray, String>, encoding: KeyEncoding? ->
|
|
51
|
+
val bytes = if (input.`is`(ByteArray::class)) {
|
|
52
|
+
input.get(ByteArray::class)
|
|
53
|
+
} else {
|
|
54
|
+
val encodedString = input.get(String::class)
|
|
55
|
+
when (encoding) {
|
|
56
|
+
null -> throw MissingStringEncodingException()
|
|
57
|
+
KeyEncoding.BASE64 -> Base64.decode(encodedString, Base64.NO_WRAP)
|
|
58
|
+
KeyEncoding.HEX ->
|
|
59
|
+
encodedString
|
|
60
|
+
.lowercase()
|
|
61
|
+
.substringAfter("0x")
|
|
62
|
+
.hexToByteArray(HexFormat.Default)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
EncryptionKey(bytes)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
AsyncFunction("bytes") { key: EncryptionKey -> key.bytes }
|
|
69
|
+
AsyncFunction("encoded") { key: EncryptionKey, encoding: KeyEncoding ->
|
|
70
|
+
key.bytes.encoded(encoding)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Property("size") { key: EncryptionKey -> key.keySize }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Class("SealedData", SealedData::class) {
|
|
77
|
+
Constructor {
|
|
78
|
+
throw Exceptions.IllegalArgument("SealedData constructor cannot be used directly")
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
StaticFunction("fromParts", this@AesCryptoModule::sealedDataFromParts)
|
|
82
|
+
StaticFunction("fromCombined") { combined: ByteArray, config: SealedDataConfig? ->
|
|
83
|
+
val config = config ?: SealedDataConfig()
|
|
84
|
+
SealedData(config, content = combined)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
AsyncFunction("iv") { sealedData: SealedData, format: DataFormat? ->
|
|
88
|
+
sealedData.ivBytes.formatted(format)
|
|
89
|
+
}
|
|
90
|
+
AsyncFunction("tag") { sealedData: SealedData, format: DataFormat? ->
|
|
91
|
+
sealedData.tagBytes.formatted(format)
|
|
92
|
+
}
|
|
93
|
+
AsyncFunction("combined") { sealedData: SealedData, format: DataFormat? ->
|
|
94
|
+
sealedData.combinedArray.formatted(format)
|
|
95
|
+
}
|
|
96
|
+
AsyncFunction("ciphertext") { sealedData: SealedData, options: CiphertextOptions? ->
|
|
97
|
+
val (includeTag, outputFormat) = options ?: CiphertextOptions()
|
|
98
|
+
sealedData.ciphertextBytes(withTag = includeTag).formatted(outputFormat)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Property("combinedSize") { sealedData -> sealedData.combinedSize }
|
|
102
|
+
Property("ivSize") { sealedData -> sealedData.ivSize }
|
|
103
|
+
Property("tagSize") { sealedData -> sealedData.tagSize }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private fun encrypt(
|
|
108
|
+
plaintext: BinaryInput,
|
|
109
|
+
key: EncryptionKey,
|
|
110
|
+
options: EncryptOptions?
|
|
111
|
+
): SealedData {
|
|
112
|
+
val key = key.cryptoKey
|
|
113
|
+
val plaintextBuffer = ByteBuffer.wrap(plaintext.toBytes())
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION_NAME).apply {
|
|
117
|
+
val params = options?.gcmParameterSpec(rng)
|
|
118
|
+
init(Cipher.ENCRYPT_MODE, key, params)
|
|
119
|
+
options?.additionalData?.let { updateAAD(it.toBytes()) }
|
|
120
|
+
}
|
|
121
|
+
return cipher.encrypt(plaintextBuffer)
|
|
122
|
+
} catch (err: Throwable) {
|
|
123
|
+
throw EncryptionFailed(err)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private fun decrypt(
|
|
128
|
+
sealedData: SealedData,
|
|
129
|
+
key: EncryptionKey,
|
|
130
|
+
options: DecryptOptions?
|
|
131
|
+
): Any {
|
|
132
|
+
val key = key.cryptoKey
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION_NAME).apply {
|
|
136
|
+
val spec = GCMParameterSpec(sealedData.tagSize * 8, sealedData.ivBytes)
|
|
137
|
+
init(Cipher.DECRYPT_MODE, key, spec)
|
|
138
|
+
}
|
|
139
|
+
options?.additionalData?.let { cipher.updateAAD(it.toBytes()) }
|
|
140
|
+
|
|
141
|
+
val plaintext = cipher.decrypt(sealedData)
|
|
142
|
+
return plaintext.array().formatted(options?.output)
|
|
143
|
+
} catch (err: Throwable) {
|
|
144
|
+
throw DecryptionFailed(err)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private fun sealedDataFromParts(iv: BinaryInput, ciphertext: BinaryInput, tag: Either<ByteArray, Int>?): SealedData {
|
|
149
|
+
val iv = iv.toBytes()
|
|
150
|
+
val ciphertext = ciphertext.toBytes()
|
|
151
|
+
return if (tag?.`is`(Int::class) == true) {
|
|
152
|
+
val tagLength = tag.get(Int::class)
|
|
153
|
+
SealedData(iv, ciphertext, tagLength)
|
|
154
|
+
} else if (tag?.`is`(ByteArray::class) == true) {
|
|
155
|
+
val tag = tag.get(ByteArray::class)
|
|
156
|
+
SealedData(iv, ciphertext + tag, tag.size)
|
|
157
|
+
} else {
|
|
158
|
+
SealedData(iv, ciphertext, DEFAULT_TAG_SIZE)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private fun BinaryInput.toBytes(): ByteArray {
|
|
163
|
+
if (this.`is`(ByteArray::class)) {
|
|
164
|
+
return this.get(ByteArray::class)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return Base64.decode(this.get(String::class), Base64.NO_WRAP)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package expo.modules.crypto.aes
|
|
2
|
+
|
|
3
|
+
import expo.modules.core.errors.CodedException
|
|
4
|
+
|
|
5
|
+
class MissingStringEncodingException :
|
|
6
|
+
CodedException("'encoding' argument must be provided for string input")
|
|
7
|
+
|
|
8
|
+
class InvalidKeyLengthException(byteLength: Int) :
|
|
9
|
+
CodedException("EncryptionKey cannot be created from bytes of length '$byteLength'")
|
|
10
|
+
|
|
11
|
+
class InvalidSealedDataConfigException :
|
|
12
|
+
CodedException("Invalid SealedData config")
|
|
13
|
+
|
|
14
|
+
class EncryptionFailed(cause: Throwable) :
|
|
15
|
+
CodedException("AES encryption failed: ${cause.message}", cause)
|
|
16
|
+
|
|
17
|
+
class DecryptionFailed(cause: Throwable) :
|
|
18
|
+
CodedException("AES decryption failed: ${cause.message}", cause)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.enums
|
|
2
|
+
|
|
3
|
+
import expo.modules.crypto.aes.InvalidKeyLengthException
|
|
4
|
+
import expo.modules.kotlin.types.Enumerable
|
|
5
|
+
|
|
6
|
+
enum class KeySize(val bitSize: Int) : Enumerable {
|
|
7
|
+
AES128(128),
|
|
8
|
+
AES192(192),
|
|
9
|
+
AES256(256);
|
|
10
|
+
|
|
11
|
+
val byteSize: Int
|
|
12
|
+
get() = bitSize / 8
|
|
13
|
+
|
|
14
|
+
companion object {
|
|
15
|
+
fun fromByteLength(byteLen: Int): KeySize =
|
|
16
|
+
entries.find { it.byteSize == byteLen }
|
|
17
|
+
?: throw InvalidKeyLengthException(byteLen)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.extensions
|
|
2
|
+
|
|
3
|
+
import android.util.Base64
|
|
4
|
+
import expo.modules.crypto.aes.enums.DataFormat
|
|
5
|
+
import expo.modules.crypto.aes.enums.KeyEncoding
|
|
6
|
+
import java.nio.ByteBuffer
|
|
7
|
+
|
|
8
|
+
fun ByteBuffer.copiedArray(): ByteArray =
|
|
9
|
+
ByteArray(remaining()).also { get(it) }
|
|
10
|
+
|
|
11
|
+
inline fun ByteArray.init(block: ByteBuffer.() -> Unit): ByteArray = apply {
|
|
12
|
+
ByteBuffer.wrap(this).also { block(it) }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fun ByteArray.base64Encoded(): String =
|
|
16
|
+
Base64.encodeToString(this, Base64.NO_WRAP)
|
|
17
|
+
|
|
18
|
+
fun ByteArray.hexEncoded(): String =
|
|
19
|
+
joinToString("") { "%02x".format(it) }
|
|
20
|
+
|
|
21
|
+
fun ByteArray.encoded(encoding: KeyEncoding): String =
|
|
22
|
+
when (encoding) {
|
|
23
|
+
KeyEncoding.HEX -> this.hexEncoded()
|
|
24
|
+
KeyEncoding.BASE64 -> this.base64Encoded()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fun ByteArray.formatted(format: DataFormat?): Any =
|
|
28
|
+
when (format) {
|
|
29
|
+
DataFormat.BYTES, null -> this
|
|
30
|
+
DataFormat.BASE64 -> this.base64Encoded()
|
|
31
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.extensions
|
|
2
|
+
|
|
3
|
+
import expo.modules.crypto.aes.objects.SealedData
|
|
4
|
+
import java.nio.ByteBuffer
|
|
5
|
+
import javax.crypto.Cipher
|
|
6
|
+
|
|
7
|
+
internal fun Cipher.encrypt(plaintext: ByteBuffer): SealedData {
|
|
8
|
+
val plaintextSize = plaintext.remaining()
|
|
9
|
+
val ciphertextWithTagSize = getOutputSize(plaintextSize)
|
|
10
|
+
val tagSize = ciphertextWithTagSize - plaintextSize
|
|
11
|
+
|
|
12
|
+
return SealedData(iv, plaintextSize, tagSize).also {
|
|
13
|
+
doFinal(plaintext, it.taggedCiphertextBuffer)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
internal fun Cipher.decrypt(sealedData: SealedData): ByteBuffer {
|
|
18
|
+
val inputBuf = sealedData.taggedCiphertextBuffer
|
|
19
|
+
val plaintextSize = getOutputSize(inputBuf.remaining())
|
|
20
|
+
|
|
21
|
+
return ByteBuffer.allocate(plaintextSize).also { outputBuf ->
|
|
22
|
+
doFinal(inputBuf, outputBuf)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.objects
|
|
2
|
+
|
|
3
|
+
import expo.modules.crypto.aes.AesConfig.CRYPTO_KEY_ALGORITHM
|
|
4
|
+
import expo.modules.crypto.aes.enums.KeySize
|
|
5
|
+
import expo.modules.kotlin.sharedobjects.SharedObject
|
|
6
|
+
import javax.crypto.KeyGenerator
|
|
7
|
+
import javax.crypto.SecretKey
|
|
8
|
+
import javax.crypto.spec.SecretKeySpec
|
|
9
|
+
|
|
10
|
+
class EncryptionKey : SharedObject {
|
|
11
|
+
val keySize: KeySize
|
|
12
|
+
val cryptoKey: SecretKey
|
|
13
|
+
|
|
14
|
+
constructor(size: KeySize) {
|
|
15
|
+
val keygen = KeyGenerator.getInstance(CRYPTO_KEY_ALGORITHM).apply {
|
|
16
|
+
init(size.bitSize)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
keySize = size
|
|
20
|
+
cryptoKey = keygen.generateKey()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
constructor(bytes: ByteArray) {
|
|
24
|
+
keySize = KeySize.fromByteLength(bytes.size)
|
|
25
|
+
cryptoKey = SecretKeySpec(bytes, CRYPTO_KEY_ALGORITHM)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
val bytes: ByteArray
|
|
29
|
+
get() = cryptoKey.encoded
|
|
30
|
+
|
|
31
|
+
override fun getAdditionalMemoryPressure(): Int = keySize.byteSize
|
|
32
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.objects
|
|
2
|
+
|
|
3
|
+
import expo.modules.crypto.aes.InvalidSealedDataConfigException
|
|
4
|
+
import expo.modules.crypto.aes.extensions.copiedArray
|
|
5
|
+
import expo.modules.crypto.aes.extensions.init
|
|
6
|
+
import expo.modules.crypto.aes.records.SealedDataConfig
|
|
7
|
+
import expo.modules.kotlin.sharedobjects.SharedObject
|
|
8
|
+
import java.nio.ByteBuffer
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents a contiguous memory area containing concatenated IV || ciphertext || tag.
|
|
12
|
+
*/
|
|
13
|
+
class SealedData(
|
|
14
|
+
private val config: SealedDataConfig,
|
|
15
|
+
private val content: ByteArray
|
|
16
|
+
) : SharedObject() {
|
|
17
|
+
init {
|
|
18
|
+
if (content.size < ivSize + tagSize) {
|
|
19
|
+
throw InvalidSealedDataConfigException()
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Initializes sealed data with given IV, and allocates memory for ciphertext and tag.
|
|
25
|
+
*/
|
|
26
|
+
constructor(iv: ByteArray, ciphertextLength: Int, tagLength: Int) : this(
|
|
27
|
+
config = SealedDataConfig(ivLength = iv.size, tagLength = tagLength),
|
|
28
|
+
content = ByteArray(iv.size + ciphertextLength + tagLength).init {
|
|
29
|
+
put(iv)
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Constructs sealed data from parts.
|
|
35
|
+
*/
|
|
36
|
+
constructor(iv: ByteArray, ciphertextWithTag: ByteArray, tagLength: Int) : this(
|
|
37
|
+
config = SealedDataConfig(ivLength = iv.size, tagLength = tagLength),
|
|
38
|
+
content = iv + ciphertextWithTag
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
// buffers mapping specific memory regions
|
|
42
|
+
private val ivBuffer: ByteBuffer
|
|
43
|
+
get() = ByteBuffer.wrap(content, 0, ivSize)
|
|
44
|
+
private val tagBuffer: ByteBuffer
|
|
45
|
+
get() = ByteBuffer.wrap(content, content.size - tagSize, tagSize)
|
|
46
|
+
private val combinedBuffer: ByteBuffer
|
|
47
|
+
get() = ByteBuffer.wrap(content)
|
|
48
|
+
private val ciphertextBuffer: ByteBuffer
|
|
49
|
+
get() = ByteBuffer.wrap(content, ivSize, ciphertextSize)
|
|
50
|
+
|
|
51
|
+
/** Buffer used by `[javax.crypto.Cipher]` to perform encryption/decryption */
|
|
52
|
+
internal val taggedCiphertextBuffer: ByteBuffer
|
|
53
|
+
get() = ByteBuffer.wrap(content, ivSize, ciphertextSize + tagSize)
|
|
54
|
+
|
|
55
|
+
val combinedSize: Int
|
|
56
|
+
get() = content.size
|
|
57
|
+
val ivSize: Int
|
|
58
|
+
get() = config.ivLength
|
|
59
|
+
val tagSize: Int
|
|
60
|
+
get() = config.tagLength
|
|
61
|
+
val ciphertextSize: Int
|
|
62
|
+
get() = combinedSize - ivSize - tagSize
|
|
63
|
+
|
|
64
|
+
val ivBytes: ByteArray
|
|
65
|
+
get() = ivBuffer.copiedArray()
|
|
66
|
+
val tagBytes: ByteArray
|
|
67
|
+
get() = tagBuffer.copiedArray()
|
|
68
|
+
val combinedArray: ByteArray
|
|
69
|
+
get() = combinedBuffer.array()
|
|
70
|
+
|
|
71
|
+
fun ciphertextBytes(withTag: Boolean): ByteArray =
|
|
72
|
+
if (withTag) {
|
|
73
|
+
taggedCiphertextBuffer
|
|
74
|
+
} else {
|
|
75
|
+
ciphertextBuffer
|
|
76
|
+
}.copiedArray()
|
|
77
|
+
|
|
78
|
+
override fun getAdditionalMemoryPressure(): Int = content.size
|
|
79
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.records
|
|
2
|
+
|
|
3
|
+
import expo.modules.crypto.aes.enums.DataFormat
|
|
4
|
+
import expo.modules.kotlin.records.Field
|
|
5
|
+
import expo.modules.kotlin.records.Record
|
|
6
|
+
|
|
7
|
+
data class CiphertextOptions(
|
|
8
|
+
@Field val includeTag: Boolean = false,
|
|
9
|
+
@Field val outputFormat: DataFormat = DataFormat.BYTES
|
|
10
|
+
) : Record
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.records
|
|
2
|
+
|
|
3
|
+
import expo.modules.crypto.aes.BinaryInput
|
|
4
|
+
import expo.modules.crypto.aes.enums.DataFormat
|
|
5
|
+
import expo.modules.kotlin.apifeatures.EitherType
|
|
6
|
+
import expo.modules.kotlin.records.Field
|
|
7
|
+
import expo.modules.kotlin.records.Record
|
|
8
|
+
|
|
9
|
+
@OptIn(EitherType::class)
|
|
10
|
+
class DecryptOptions : Record {
|
|
11
|
+
@Field
|
|
12
|
+
val output: DataFormat = DataFormat.BYTES
|
|
13
|
+
|
|
14
|
+
@Field
|
|
15
|
+
val additionalData: BinaryInput? = null
|
|
16
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.records
|
|
2
|
+
|
|
3
|
+
import android.util.Base64
|
|
4
|
+
import expo.modules.crypto.aes.AesConfig.DEFAULT_IV_SIZE
|
|
5
|
+
import expo.modules.crypto.aes.AesConfig.DEFAULT_TAG_SIZE
|
|
6
|
+
import expo.modules.crypto.aes.BinaryInput
|
|
7
|
+
import expo.modules.kotlin.apifeatures.EitherType
|
|
8
|
+
import expo.modules.kotlin.records.Field
|
|
9
|
+
import expo.modules.kotlin.records.Record
|
|
10
|
+
import expo.modules.kotlin.types.EitherOfThree
|
|
11
|
+
import java.security.SecureRandom
|
|
12
|
+
import javax.crypto.spec.GCMParameterSpec
|
|
13
|
+
|
|
14
|
+
@OptIn(EitherType::class)
|
|
15
|
+
class EncryptOptions : Record {
|
|
16
|
+
@Field
|
|
17
|
+
val nonce: EitherOfThree<String, ByteArray, Int>? = null
|
|
18
|
+
|
|
19
|
+
@Field
|
|
20
|
+
val tagLength: Int? = null
|
|
21
|
+
|
|
22
|
+
@Field
|
|
23
|
+
val additionalData: BinaryInput? = null
|
|
24
|
+
|
|
25
|
+
internal fun gcmParameterSpec(random: SecureRandom): GCMParameterSpec? {
|
|
26
|
+
// a default will be generated by Cipher
|
|
27
|
+
if (nonce == null && tagLength == null) {
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
val iv = if (nonce == null) {
|
|
32
|
+
ByteArray(DEFAULT_IV_SIZE).also { random.nextBytes(it) }
|
|
33
|
+
} else if (nonce.`is`(Int::class)) {
|
|
34
|
+
ByteArray(nonce.get(Int::class)).also { random.nextBytes(it) }
|
|
35
|
+
} else if (nonce.`is`(String::class)) {
|
|
36
|
+
Base64.decode(nonce.get(String::class), Base64.NO_WRAP)
|
|
37
|
+
} else {
|
|
38
|
+
nonce.get(ByteArray::class)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
val tagByteLength = tagLength ?: DEFAULT_TAG_SIZE
|
|
42
|
+
return GCMParameterSpec(tagByteLength * 8, iv)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
package expo.modules.crypto.aes.records
|
|
2
|
+
|
|
3
|
+
import expo.modules.crypto.aes.AesConfig.DEFAULT_IV_SIZE
|
|
4
|
+
import expo.modules.crypto.aes.AesConfig.DEFAULT_TAG_SIZE
|
|
5
|
+
import expo.modules.kotlin.records.Field
|
|
6
|
+
import expo.modules.kotlin.records.Record
|
|
7
|
+
|
|
8
|
+
data class SealedDataConfig(
|
|
9
|
+
@Field val ivLength: Int = DEFAULT_IV_SIZE,
|
|
10
|
+
@Field val tagLength: Int = DEFAULT_TAG_SIZE
|
|
11
|
+
) : Record
|
package/build/Crypto.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { UintBasedTypedArray, IntBasedTypedArray } from 'expo-modules-core';
|
|
2
2
|
import { CryptoDigestAlgorithm, CryptoDigestOptions, Digest } from './Crypto.types';
|
|
3
3
|
export * from './Crypto.types';
|
|
4
|
+
export * from './aes';
|
|
4
5
|
/**
|
|
5
6
|
* Generates completely random bytes using native implementations. The `byteCount` property
|
|
6
7
|
* is a `number` indicating the number of bytes to generate in the form of a `Uint8Array`.
|
package/build/Crypto.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Crypto.d.ts","sourceRoot":"","sources":["../src/Crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEjG,OAAO,EAAE,qBAAqB,EAAkB,mBAAmB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAKpG,cAAc,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"Crypto.d.ts","sourceRoot":"","sources":["../src/Crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEjG,OAAO,EAAE,qBAAqB,EAAkB,mBAAmB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAKpG,cAAc,gBAAgB,CAAC;AAC/B,cAAc,OAAO,CAAC;AAWtB;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAoB5D;AAGD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAUhF;AA0CD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,qBAAqB,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAsD,GAC9D,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,kBAAkB,GAAG,mBAAmB,EAChF,UAAU,EAAE,CAAC,GACZ,CAAC,CAGH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAYD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,MAAM,CAAC,SAAS,EAAE,qBAAqB,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAcjG"}
|
package/build/Crypto.js
CHANGED
|
@@ -2,6 +2,7 @@ import { UnavailabilityError } from 'expo-modules-core';
|
|
|
2
2
|
import { CryptoDigestAlgorithm, CryptoEncoding } from './Crypto.types';
|
|
3
3
|
import ExpoCrypto from './ExpoCrypto';
|
|
4
4
|
export * from './Crypto.types';
|
|
5
|
+
export * from './aes';
|
|
5
6
|
class CryptoError extends TypeError {
|
|
6
7
|
code = 'ERR_CRYPTO';
|
|
7
8
|
constructor(message) {
|
package/build/Crypto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Crypto.js","sourceRoot":"","sources":["../src/Crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAA2C,MAAM,mBAAmB,CAAC;AAEjG,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAA+B,MAAM,gBAAgB,CAAC;AACpG,OAAO,UAAU,MAAM,cAAc,CAAC;AAItC,cAAc,gBAAgB,CAAC;AAE/B,MAAM,WAAY,SAAQ,SAAS;IACjC,IAAI,GAAG,YAAY,CAAC;IAEpB,YAAY,OAAe;QACzB,KAAK,CAAC,gBAAgB,OAAO,EAAE,CAAC,CAAC;IACnC,CAAC;CACF;AAED,cAAc;AACd;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,eAAe,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAC7C,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC,MAAM,CAAC,kBAAkB,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACvD,yCAAyC;YACzC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,cAAc,CAAC,CAAC;YAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,EAAE,CAAC,EAAE,EAAE,CAAC;gBACxC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,eAAe,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,cAAc,CAAC,CAAC;QACjD,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QACtC,OAAO,SAAS,CAAC;IACnB,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,mBAAmB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,SAAiB;IACzD,eAAe,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,UAAU,CAAC,eAAe,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,cAAc,CAAC,CAAC;QACjD,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QACtC,OAAO,SAAS,CAAC;IACnB,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,mBAAmB,CAAC,aAAa,EAAE,qBAAqB,CAAC,CAAC;IACtE,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAU,EAAE,UAAkB;IACrD,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,KAAK,CAAC;QACZ,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,EACxB,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,gBAAgB,UAAU,IAAI,KAAK,+CAA+C,CACnF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,SAAgC;IACvD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,WAAW,CACnB,sEAAsE,MAAM,CAAC,IAAI,CAC/E,qBAAqB,CACtB,CAAC,IAAI,CAAC,mCAAmC,CAAC,EAAE,CAC9C,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,IAAI,WAAW,CAAC,2CAA2C,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,QAAwB;IAC9C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,WAAW,CACnB,8DAA8D,MAAM,CAAC,IAAI,CACvE,cAAc,CACf,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAC9B,CAAC;IACJ,CAAC;AACH,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,SAAgC,EAChC,IAAY,EACZ,UAA+B,EAAE,QAAQ,EAAE,cAAc,CAAC,GAAG,EAAE;IAE/D,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC;QAClC,MAAM,IAAI,mBAAmB,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAAC;IACpE,CAAC;IAED,eAAe,CAAC,SAAS,CAAC,CAAC;IAC3B,UAAU,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEjC,OAAO,MAAM,UAAU,CAAC,iBAAiB,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAC7B,UAAa;IAEb,UAAU,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;IACvC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,UAAU,CAAC,UAAU,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,aAAa,GAAG;IACpB,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,EAAE;IAChC,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,EAAE;IAClC,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,EAAE;IAClC,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,EAAE;IAClC,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,EAAE;IAC/B,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,EAAE;IAC/B,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,EAAE;CAChC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,MAAM,CAAC,SAAgC,EAAE,IAAkB;IACzE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,IAAI,OAAO,UAAU,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;gBACjD,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YACnD,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;gBACxD,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;gBAC3C,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { UnavailabilityError, UintBasedTypedArray, IntBasedTypedArray } from 'expo-modules-core';\n\nimport { CryptoDigestAlgorithm, CryptoEncoding, CryptoDigestOptions, Digest } from './Crypto.types';\nimport ExpoCrypto from './ExpoCrypto';\n\ndeclare const global: any;\n\nexport * from './Crypto.types';\n\nclass CryptoError extends TypeError {\n code = 'ERR_CRYPTO';\n\n constructor(message: string) {\n super(`expo-crypto: ${message}`);\n }\n}\n\n// @needsAudit\n/**\n * Generates completely random bytes using native implementations. The `byteCount` property\n * is a `number` indicating the number of bytes to generate in the form of a `Uint8Array`.\n * Falls back to `Math.random` during development to prevent issues with React Native Debugger.\n * @param byteCount - A number within the range from `0` to `1024`. Anything else will throw a `TypeError`.\n * @return An array of random bytes with the same length as the `byteCount`.\n */\nexport function getRandomBytes(byteCount: number): Uint8Array {\n assertByteCount(byteCount, 'getRandomBytes');\n const validByteCount = Math.floor(byteCount);\n if (__DEV__) {\n if (!global.nativeCallSyncHook || global.__REMOTEDEV__) {\n // remote javascript debugging is enabled\n const array = new Uint8Array(validByteCount);\n for (let i = 0; i < validByteCount; i++) {\n array[i] = Math.floor(Math.random() * 256);\n }\n return array;\n }\n }\n if (ExpoCrypto.getRandomValues) {\n const byteArray = new Uint8Array(validByteCount);\n ExpoCrypto.getRandomValues(byteArray);\n return byteArray;\n } else {\n throw new UnavailabilityError('expo-crypto', 'getRandomBytes');\n }\n}\n\n// @needsAudit\n/**\n * Generates completely random bytes using native implementations. The `byteCount` property\n * is a `number` indicating the number of bytes to generate in the form of a `Uint8Array`.\n * @param byteCount - A number within the range from `0` to `1024`. Anything else will throw a `TypeError`.\n * @return A promise that fulfills with an array of random bytes with the same length as the `byteCount`.\n */\nexport async function getRandomBytesAsync(byteCount: number): Promise<Uint8Array> {\n assertByteCount(byteCount, 'getRandomBytesAsync');\n const validByteCount = Math.floor(byteCount);\n if (ExpoCrypto.getRandomValues) {\n const byteArray = new Uint8Array(validByteCount);\n ExpoCrypto.getRandomValues(byteArray);\n return byteArray;\n } else {\n throw new UnavailabilityError('expo-crypto', 'getRandomBytesAsync');\n }\n}\n\nfunction assertByteCount(value: any, methodName: string): void {\n if (\n typeof value !== 'number' ||\n isNaN(value) ||\n Math.floor(value) < 0 ||\n Math.floor(value) > 1024\n ) {\n throw new TypeError(\n `expo-crypto: ${methodName}(${value}) expected a valid number from range 0...1024`\n );\n }\n}\n\nfunction assertAlgorithm(algorithm: CryptoDigestAlgorithm): void {\n if (!Object.values(CryptoDigestAlgorithm).includes(algorithm)) {\n throw new CryptoError(\n `Invalid algorithm provided. Expected one of: CryptoDigestAlgorithm.${Object.keys(\n CryptoDigestAlgorithm\n ).join(', AlgCryptoDigestAlgorithmorithm.')}`\n );\n }\n}\n\nfunction assertData(data: string): void {\n if (typeof data !== 'string') {\n throw new CryptoError(`Invalid data provided. Expected a string.`);\n }\n}\n\nfunction assertEncoding(encoding: CryptoEncoding): void {\n if (!Object.values(CryptoEncoding).includes(encoding)) {\n throw new CryptoError(\n `Invalid encoding provided. Expected one of: CryptoEncoding.${Object.keys(\n CryptoEncoding\n ).join(', CryptoEncoding.')}`\n );\n }\n}\n\n// @needsAudit\n/**\n * The `digestStringAsync()` method of `Crypto` generates a digest of the supplied `data` string with the provided digest `algorithm`.\n * A digest is a short fixed-length value derived from some variable-length input. **Cryptographic digests** should exhibit _collision-resistance_,\n * meaning that it's very difficult to generate multiple inputs that have equal digest values.\n * You can specify the returned string format as one of `CryptoEncoding`. By default, the resolved value will be formatted as a `HEX` string.\n * On web, this method can only be called from a secure origin (HTTPS) otherwise, an error will be thrown.\n *\n * @param algorithm The cryptographic hash function to use to transform a block of data into a fixed-size output.\n * @param data The value that will be used to generate a digest.\n * @param options Format of the digest string. Defaults to: `CryptoDigestOptions.HEX`.\n * @return Return a Promise which fulfills with a value representing the hashed input.\n *\n * @example\n * ```ts\n * const digest = await Crypto.digestStringAsync(\n * Crypto.CryptoDigestAlgorithm.SHA512,\n * '🥓 Easy to Digest! 💙'\n * );\n * ```\n */\nexport async function digestStringAsync(\n algorithm: CryptoDigestAlgorithm,\n data: string,\n options: CryptoDigestOptions = { encoding: CryptoEncoding.HEX }\n): Promise<Digest> {\n if (!ExpoCrypto.digestStringAsync) {\n throw new UnavailabilityError('expo-crypto', 'digestStringAsync');\n }\n\n assertAlgorithm(algorithm);\n assertData(data);\n assertEncoding(options.encoding);\n\n return await ExpoCrypto.digestStringAsync(algorithm, data, options);\n}\n\n/**\n * The `getRandomValues()` method of `Crypto` fills a provided `TypedArray` with cryptographically secure random values.\n *\n * @param typedArray An integer based [`TypedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) to fill with cryptographically secure random values. It modifies the input array in place.\n * @return The input array filled with cryptographically secure random values.\n *\n * @example\n * ```ts\n * const byteArray = new Uint8Array(16);\n * Crypto.getRandomValues(byteArray);\n * console.log('Your lucky bytes: ' + byteArray);\n * ```\n */\nexport function getRandomValues<T extends IntBasedTypedArray | UintBasedTypedArray>(\n typedArray: T\n): T {\n ExpoCrypto.getRandomValues(typedArray);\n return typedArray;\n}\n\n/**\n * The `randomUUID()` method returns a unique identifier based on the V4 UUID spec (RFC4122).\n * It uses cryptographically secure random values to generate the UUID.\n *\n * @return A string containing a newly generated UUIDv4 identifier\n * @example\n * ```ts\n * const UUID = Crypto.randomUUID();\n * console.log('Your UUID: ' + UUID);\n * ```\n */\nexport function randomUUID(): string {\n return ExpoCrypto.randomUUID();\n}\n\nconst digestLengths = {\n [CryptoDigestAlgorithm.SHA1]: 20,\n [CryptoDigestAlgorithm.SHA256]: 32,\n [CryptoDigestAlgorithm.SHA384]: 48,\n [CryptoDigestAlgorithm.SHA512]: 64,\n [CryptoDigestAlgorithm.MD2]: 16,\n [CryptoDigestAlgorithm.MD4]: 16,\n [CryptoDigestAlgorithm.MD5]: 16,\n};\n\n/**\n * The `digest()` method of `Crypto` generates a digest of the supplied `TypedArray` of bytes `data` with the provided digest `algorithm`.\n * A digest is a short fixed-length value derived from some variable-length input. **Cryptographic digests** should exhibit _collision-resistance_,\n * meaning that it's very difficult to generate multiple inputs that have equal digest values.\n * On web, this method can only be called from a secure origin (HTTPS) otherwise, an error will be thrown.\n *\n * @param algorithm The cryptographic hash function to use to transform a block of data into a fixed-size output.\n * @param data The value that will be used to generate a digest.\n * @return A Promise which fulfills with an ArrayBuffer representing the hashed input.\n * @example\n * ```ts\n * const array = new Uint8Array([1, 2, 3, 4, 5]);\n * const digest = await Crypto.digest(Crypto.CryptoDigestAlgorithm.SHA512, array);\n * console.log('Your digest: ' + digest);\n * ```\n */\nexport function digest(algorithm: CryptoDigestAlgorithm, data: BufferSource): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n try {\n if (typeof ExpoCrypto.digestAsync === 'function') {\n resolve(ExpoCrypto.digestAsync(algorithm, data));\n } else {\n const output = new Uint8Array(digestLengths[algorithm]);\n ExpoCrypto.digest(algorithm, output, data);\n resolve(output.buffer);\n }\n } catch (error) {\n reject(error);\n }\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Crypto.js","sourceRoot":"","sources":["../src/Crypto.ts"],"names":[],"mappings":"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","sourcesContent":["import { UnavailabilityError, UintBasedTypedArray, IntBasedTypedArray } from 'expo-modules-core';\n\nimport { CryptoDigestAlgorithm, CryptoEncoding, CryptoDigestOptions, Digest } from './Crypto.types';\nimport ExpoCrypto from './ExpoCrypto';\n\ndeclare const global: any;\n\nexport * from './Crypto.types';\nexport * from './aes';\n\nclass CryptoError extends TypeError {\n code = 'ERR_CRYPTO';\n\n constructor(message: string) {\n super(`expo-crypto: ${message}`);\n }\n}\n\n// @needsAudit\n/**\n * Generates completely random bytes using native implementations. The `byteCount` property\n * is a `number` indicating the number of bytes to generate in the form of a `Uint8Array`.\n * Falls back to `Math.random` during development to prevent issues with React Native Debugger.\n * @param byteCount - A number within the range from `0` to `1024`. Anything else will throw a `TypeError`.\n * @return An array of random bytes with the same length as the `byteCount`.\n */\nexport function getRandomBytes(byteCount: number): Uint8Array {\n assertByteCount(byteCount, 'getRandomBytes');\n const validByteCount = Math.floor(byteCount);\n if (__DEV__) {\n if (!global.nativeCallSyncHook || global.__REMOTEDEV__) {\n // remote javascript debugging is enabled\n const array = new Uint8Array(validByteCount);\n for (let i = 0; i < validByteCount; i++) {\n array[i] = Math.floor(Math.random() * 256);\n }\n return array;\n }\n }\n if (ExpoCrypto.getRandomValues) {\n const byteArray = new Uint8Array(validByteCount);\n ExpoCrypto.getRandomValues(byteArray);\n return byteArray;\n } else {\n throw new UnavailabilityError('expo-crypto', 'getRandomBytes');\n }\n}\n\n// @needsAudit\n/**\n * Generates completely random bytes using native implementations. The `byteCount` property\n * is a `number` indicating the number of bytes to generate in the form of a `Uint8Array`.\n * @param byteCount - A number within the range from `0` to `1024`. Anything else will throw a `TypeError`.\n * @return A promise that fulfills with an array of random bytes with the same length as the `byteCount`.\n */\nexport async function getRandomBytesAsync(byteCount: number): Promise<Uint8Array> {\n assertByteCount(byteCount, 'getRandomBytesAsync');\n const validByteCount = Math.floor(byteCount);\n if (ExpoCrypto.getRandomValues) {\n const byteArray = new Uint8Array(validByteCount);\n ExpoCrypto.getRandomValues(byteArray);\n return byteArray;\n } else {\n throw new UnavailabilityError('expo-crypto', 'getRandomBytesAsync');\n }\n}\n\nfunction assertByteCount(value: any, methodName: string): void {\n if (\n typeof value !== 'number' ||\n isNaN(value) ||\n Math.floor(value) < 0 ||\n Math.floor(value) > 1024\n ) {\n throw new TypeError(\n `expo-crypto: ${methodName}(${value}) expected a valid number from range 0...1024`\n );\n }\n}\n\nfunction assertAlgorithm(algorithm: CryptoDigestAlgorithm): void {\n if (!Object.values(CryptoDigestAlgorithm).includes(algorithm)) {\n throw new CryptoError(\n `Invalid algorithm provided. Expected one of: CryptoDigestAlgorithm.${Object.keys(\n CryptoDigestAlgorithm\n ).join(', AlgCryptoDigestAlgorithmorithm.')}`\n );\n }\n}\n\nfunction assertData(data: string): void {\n if (typeof data !== 'string') {\n throw new CryptoError(`Invalid data provided. Expected a string.`);\n }\n}\n\nfunction assertEncoding(encoding: CryptoEncoding): void {\n if (!Object.values(CryptoEncoding).includes(encoding)) {\n throw new CryptoError(\n `Invalid encoding provided. Expected one of: CryptoEncoding.${Object.keys(\n CryptoEncoding\n ).join(', CryptoEncoding.')}`\n );\n }\n}\n\n// @needsAudit\n/**\n * The `digestStringAsync()` method of `Crypto` generates a digest of the supplied `data` string with the provided digest `algorithm`.\n * A digest is a short fixed-length value derived from some variable-length input. **Cryptographic digests** should exhibit _collision-resistance_,\n * meaning that it's very difficult to generate multiple inputs that have equal digest values.\n * You can specify the returned string format as one of `CryptoEncoding`. By default, the resolved value will be formatted as a `HEX` string.\n * On web, this method can only be called from a secure origin (HTTPS) otherwise, an error will be thrown.\n *\n * @param algorithm The cryptographic hash function to use to transform a block of data into a fixed-size output.\n * @param data The value that will be used to generate a digest.\n * @param options Format of the digest string. Defaults to: `CryptoDigestOptions.HEX`.\n * @return Return a Promise which fulfills with a value representing the hashed input.\n *\n * @example\n * ```ts\n * const digest = await Crypto.digestStringAsync(\n * Crypto.CryptoDigestAlgorithm.SHA512,\n * '🥓 Easy to Digest! 💙'\n * );\n * ```\n */\nexport async function digestStringAsync(\n algorithm: CryptoDigestAlgorithm,\n data: string,\n options: CryptoDigestOptions = { encoding: CryptoEncoding.HEX }\n): Promise<Digest> {\n if (!ExpoCrypto.digestStringAsync) {\n throw new UnavailabilityError('expo-crypto', 'digestStringAsync');\n }\n\n assertAlgorithm(algorithm);\n assertData(data);\n assertEncoding(options.encoding);\n\n return await ExpoCrypto.digestStringAsync(algorithm, data, options);\n}\n\n/**\n * The `getRandomValues()` method of `Crypto` fills a provided `TypedArray` with cryptographically secure random values.\n *\n * @param typedArray An integer based [`TypedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) to fill with cryptographically secure random values. It modifies the input array in place.\n * @return The input array filled with cryptographically secure random values.\n *\n * @example\n * ```ts\n * const byteArray = new Uint8Array(16);\n * Crypto.getRandomValues(byteArray);\n * console.log('Your lucky bytes: ' + byteArray);\n * ```\n */\nexport function getRandomValues<T extends IntBasedTypedArray | UintBasedTypedArray>(\n typedArray: T\n): T {\n ExpoCrypto.getRandomValues(typedArray);\n return typedArray;\n}\n\n/**\n * The `randomUUID()` method returns a unique identifier based on the V4 UUID spec (RFC4122).\n * It uses cryptographically secure random values to generate the UUID.\n *\n * @return A string containing a newly generated UUIDv4 identifier\n * @example\n * ```ts\n * const UUID = Crypto.randomUUID();\n * console.log('Your UUID: ' + UUID);\n * ```\n */\nexport function randomUUID(): string {\n return ExpoCrypto.randomUUID();\n}\n\nconst digestLengths = {\n [CryptoDigestAlgorithm.SHA1]: 20,\n [CryptoDigestAlgorithm.SHA256]: 32,\n [CryptoDigestAlgorithm.SHA384]: 48,\n [CryptoDigestAlgorithm.SHA512]: 64,\n [CryptoDigestAlgorithm.MD2]: 16,\n [CryptoDigestAlgorithm.MD4]: 16,\n [CryptoDigestAlgorithm.MD5]: 16,\n};\n\n/**\n * The `digest()` method of `Crypto` generates a digest of the supplied `TypedArray` of bytes `data` with the provided digest `algorithm`.\n * A digest is a short fixed-length value derived from some variable-length input. **Cryptographic digests** should exhibit _collision-resistance_,\n * meaning that it's very difficult to generate multiple inputs that have equal digest values.\n * On web, this method can only be called from a secure origin (HTTPS) otherwise, an error will be thrown.\n *\n * @param algorithm The cryptographic hash function to use to transform a block of data into a fixed-size output.\n * @param data The value that will be used to generate a digest.\n * @return A Promise which fulfills with an ArrayBuffer representing the hashed input.\n * @example\n * ```ts\n * const array = new Uint8Array([1, 2, 3, 4, 5]);\n * const digest = await Crypto.digest(Crypto.CryptoDigestAlgorithm.SHA512, array);\n * console.log('Your digest: ' + digest);\n * ```\n */\nexport function digest(algorithm: CryptoDigestAlgorithm, data: BufferSource): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n try {\n if (typeof ExpoCrypto.digestAsync === 'function') {\n resolve(ExpoCrypto.digestAsync(algorithm, data));\n } else {\n const output = new Uint8Array(digestLengths[algorithm]);\n ExpoCrypto.digest(algorithm, output, data);\n resolve(output.buffer);\n }\n } catch (error) {\n reject(error);\n }\n });\n}\n"]}
|