Skip to content

Commit a839087

Browse files
authored
Merge pull request #667 from AlexITC/crypto-api-broken
Add WebCryptoApi tests
2 parents 0c53dea + 64a2663 commit a839087

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

tests-shared/src/main/scala/org/scalajs/dom/tests/shared/BrowserTests.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import scala.scalajs.js
1717
import scala.scalajs.js.Thenable.Implicits._
1818
import scala.util.Try
1919

20-
trait BrowserTests {
20+
trait BrowserTests extends WebCryptoApiTests {
2121

2222
def read[T](reader: ReadableStreamReader[T])(values: Seq[T]): Future[Seq[T]] = {
2323
reader
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package org.scalajs.dom.tests.shared
2+
3+
import org.junit.Assert._
4+
import org.junit.Test
5+
import org.scalajs.dom
6+
import org.scalajs.dom.tests.shared.AsyncTesting._
7+
8+
import scala.scalajs.js
9+
import scala.scalajs.js.typedarray._
10+
11+
trait WebCryptoApiTests {
12+
13+
@Test final def getRandomValuesWork: Unit = {
14+
dom.webcrypto.getRandomValues(Array.ofDim[Byte](8).toTypedArray)
15+
}
16+
17+
@Test final def generateAESEncryptionKeyWorks: AsyncResult = async {
18+
generateAESEncryptionKey()
19+
}
20+
21+
@Test final def aesEncryptionDecryptionTest: AsyncResult = async {
22+
val data = "data"
23+
for {
24+
key <- generateAESEncryptionKey()
25+
iv = generateAESInitializationVector()
26+
encrypted <- aesEncrypt(key, iv, data)
27+
decrypted <- aesDecrypt(key, iv, encrypted)
28+
} yield assertEquals(data, decrypted)
29+
}
30+
31+
@Test final def aesKeyDerivationWorks: AsyncResult = async {
32+
import scalajs.js.|._
33+
34+
val derivationAlgorithm = "PBKDF2"
35+
val pbdkf2 = new dom.Pbkdf2Params {
36+
val name = derivationAlgorithm
37+
val salt: dom.BufferSource = "salt".getBytes.toTypedArray.buffer
38+
val iterations = 100.toDouble
39+
val hash: dom.HashAlgorithmIdentifier = dom.HashAlgorithm.`SHA-512`
40+
}
41+
val aesCtr = new dom.AesDerivedKeyParams {
42+
val name = "AES-GCM"
43+
val length = 256
44+
}
45+
46+
for {
47+
pbkdf2Key <- dom.crypto.subtle
48+
.importKey(
49+
dom.KeyFormat.raw,
50+
"password".getBytes.toTypedArray.buffer,
51+
derivationAlgorithm,
52+
false,
53+
js.Array(dom.KeyUsage.deriveKey, dom.KeyUsage.deriveBits)
54+
)
55+
.toFuture
56+
57+
aesKey <- dom.crypto.subtle
58+
.deriveKey(
59+
pbdkf2,
60+
pbkdf2Key,
61+
aesCtr,
62+
true,
63+
js.Array(dom.KeyUsage.encrypt, dom.KeyUsage.decrypt)
64+
)
65+
.toFuture
66+
.map(_.asInstanceOf[dom.CryptoKey])
67+
} yield assertNotNull(aesKey)
68+
}
69+
70+
private def generateAESEncryptionKey() = {
71+
dom.crypto.subtle
72+
.generateKey(
73+
new dom.AesKeyAlgorithm {
74+
val name = "AES-GCM"
75+
val length = 256
76+
},
77+
true,
78+
js.Array(dom.KeyUsage.encrypt, dom.KeyUsage.decrypt)
79+
)
80+
.toFuture
81+
.map(_.asInstanceOf[dom.CryptoKey])
82+
}
83+
84+
private def generateAESInitializationVector() = {
85+
dom.webcrypto.getRandomValues(Array.ofDim[Byte](12).toTypedArray)
86+
}
87+
88+
private def aesEncrypt(key: dom.CryptoKey, iv0: dom.BufferSource, data: String) = {
89+
dom.crypto.subtle
90+
.encrypt(
91+
new dom.AesGcmParams {
92+
val name = "AES-GCM"
93+
val iv = iv0
94+
val tagLength = 128
95+
val additionalData: dom.BufferSource = "".getBytes.toTypedArray.buffer
96+
},
97+
key,
98+
data.getBytes().toTypedArray
99+
)
100+
.toFuture
101+
.map(_.asInstanceOf[ArrayBuffer])
102+
}
103+
104+
private def aesDecrypt(key: dom.CryptoKey, iv0: dom.BufferSource, encrypted: dom.BufferSource) = {
105+
dom.crypto.subtle
106+
.decrypt(
107+
new dom.AesGcmParams {
108+
val name = "AES-GCM"
109+
val iv = iv0
110+
val tagLength = 128
111+
val additionalData: dom.BufferSource = "".getBytes.toTypedArray.buffer
112+
},
113+
key,
114+
encrypted
115+
)
116+
.toFuture
117+
.map(_.asInstanceOf[ArrayBuffer])
118+
.map { buffer =>
119+
val arr = Array.ofDim[Byte](buffer.byteLength)
120+
TypedArrayBuffer.wrap(buffer).get(arr)
121+
new String(arr, "UTF-8")
122+
}
123+
}
124+
}

0 commit comments

Comments
 (0)