Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some methods from dom.crypto are broken #668

Closed
AlexITC opened this issue Jan 12, 2022 · 7 comments · Fixed by #669
Closed

Some methods from dom.crypto are broken #668

AlexITC opened this issue Jan 12, 2022 · 7 comments · Fixed by #669
Labels

Comments

@AlexITC
Copy link
Contributor

AlexITC commented Jan 12, 2022

scala-js-dom 2.0.0 deprecated the dom.crypto.crypto API, suggesting to use dom.crypto package instead. Unfortunately, many methods (if not all) are broken.

On the other hand, dom.crypto.crypto and dom.webcrypto seem to work.

I'm yet to try all of the methods from these packages, I have tried some methods and all of them behave this way, it would be ideal to add test coverage for the package.

To showcase the problem, I have created a draft PR (#667), I'm happy to submit the test coverage and fix the integration but I'm not sure what's the acceptable way, I could just go linking the new packages to GlobalCrypto as a simple fix.

Thanks.

@armanbilge
Copy link
Member

Thanks for reporting and opening the showcase PR, much appreciated. I'm just playing with this a bit in #669 to try and understand what's wrong. Besides dom.crypto.getRandomValues, what other methods are broken? Thanks.

@AlexITC
Copy link
Contributor Author

AlexITC commented Jan 13, 2022

Hmm, I have isolated the code for key generation -> encryption -> decryption, and, they are working, I'll keep testing the other methods I depend on and get back to you.

See:

    val f = for {
      key <- dom.crypto
        .subtle.generateKey(
          dom.AesKeyAlgorithm("AES-GCM", 256),
          true,
          js.Array(dom.KeyUsage.encrypt, dom.KeyUsage.decrypt)
        )
        .toFuture
        .map(_.asInstanceOf[dom.CryptoKey])

      aesIV = dom.webcrypto.getRandomValues(Array.ofDim[Byte](12).toTypedArray)
      encrypted <- dom.crypto
        .subtle.encrypt(
          AesGcmParams(
            "AES-GCM",
            aesIV,
            "".getBytes().toTypedArray.buffer,
            128
          ),
          key,
          "data".getBytes().toTypedArray
        )
        .toFuture
        .map(_.asInstanceOf[ArrayBuffer])
      decrypted <- dom.crypto
        .subtle.decrypt(
          AesGcmParams(
            "AES-GCM",
            aesIV,
            "".getBytes().toTypedArray.buffer, // this shouldn't be necessary
            128
          ),
          key,
          encrypted
        )
        .toFuture
        .map(_.asInstanceOf[ArrayBuffer])
        .map { buffer =>
          val arr = Array.ofDim[Byte](buffer.byteLength)
          TypedArrayBuffer.wrap(buffer).get(arr)
          new String(arr, "UTF-8")
        }
    } yield dom.console.log(decrypted)

    f.onComplete {
      case Success(value) => println(s"generateKey -> encrypt -> decrypt works")
      case Failure(exception) => println(s"generateKey -> encrypt -> decrypt failed: ${exception.getMessage}")
    }

@AlexITC AlexITC changed the title Most of the dom.crypto methods are broken Some methods from dom.crypto are broken Jan 13, 2022
@armanbilge
Copy link
Member

Thanks, I appreciate your help 👍

@AlexITC
Copy link
Contributor Author

AlexITC commented Jan 13, 2022

I have tested more methods that are working:

    val pbdkf2 = dom.Pbkdf2Params("PBKDF2", "salt".getBytes.toTypedArray.buffer, 100L, "SHA-512")
    val g = for {
      pbkdf2Key <- dom.crypto.subtle
        .importKey(
          dom.KeyFormat.raw,
          "password".getBytes.toTypedArray.buffer,
          "PBKDF2",
          false,
          js.Array(dom.KeyUsage.deriveKey, dom.KeyUsage.deriveBits)
        )
        .toFuture
      _ = println(s"pbkdf2Key: $pbkdf2Key")

      aesCtr = new dom.AesDerivedKeyParams {
        val name = "AES-GCM"
        val length = 256
      }
      _ = println(s"aesCtr: $aesCtr")
      aesKey <- dom.crypto.subtle
        .deriveKey(
          pbdkf2,
          pbkdf2Key,
          aesCtr,
          true,
          js.Array(dom.KeyUsage.encrypt, dom.KeyUsage.decrypt)
        )
        .toFuture
        .map(_.asInstanceOf[dom.CryptoKey])
      _ = println(s"aesKey: $aesKey")
    } yield ()
    g.onComplete {
      case Success(value) => println(s"aesKey works")
      case Failure(exception) => println(s"aesKey failed: ${exception.getMessage}")
    }

We should be able to gather most of these into a test file.

@armanbilge
Copy link
Member

We should be able to gather most of these into a test file.

Sounds good. Maybe a separate CryptoTests like you did in #667 is a good idea, PR would be appreciated :)

@AlexITC
Copy link
Contributor Author

AlexITC commented Jan 13, 2022

I'm happy to prepare a PR, my only concern is, how should we run the tests given that junit doesn't support future-based tests? Thread.sleep doesn't work in scalajs.

@armanbilge
Copy link
Member

Ah, you should check the examples in AsyncTests. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants