From 672a40763a38c99658c233d0f34e00921a26a21c Mon Sep 17 00:00:00 2001 From: Dima Date: Wed, 28 Mar 2018 10:19:30 +0300 Subject: [PATCH] Kademlia grpc js (#99) * update scalapb, copy grpc jvm files to js * add npm dependencies * generate js code with protoc, add it to js dependencies * class facades * add workbench, write facades, testing js * fix js encryption and hashing * tested facades for kademlia grpc service * add js kademlia grpc service, refactoring * example refactoring * docs * docs * refactor versions * refac, todo * autogenerate * generate protobuf for tests --- .../fluence/crypto/algorithm/Ecdsa.scala | 5 +++-- .../crypto/facade/ecdsa/Elliptic.scala | 5 +++-- .../fluence/crypto/facade/ecdsa/Hash.scala | 5 +++-- .../fluence/crypto/hash/JsCryptoHasher.scala | 5 +++-- .../scala/fluence/crypto/JSHashSpec.scala | 20 +++++++++++++++++-- .../scala/fluence/crypto/JvmHashSpec.scala | 12 +++++++++++ 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/js/src/main/scala/fluence/crypto/algorithm/Ecdsa.scala b/js/src/main/scala/fluence/crypto/algorithm/Ecdsa.scala index e5512f9..c581488 100644 --- a/js/src/main/scala/fluence/crypto/algorithm/Ecdsa.scala +++ b/js/src/main/scala/fluence/crypto/algorithm/Ecdsa.scala @@ -29,6 +29,7 @@ import scodec.bits.ByteVector import scala.language.higherKinds import scala.scalajs.js import scala.scalajs.js.JSConverters._ +import scala.scalajs.js.typedarray.Uint8Array /** * Return in all js methods hex, because in the other case we will receive javascript objects @@ -56,7 +57,7 @@ class Ecdsa(ec: EC, hasher: Option[CryptoHasher[Array[Byte], Array[Byte]]]) ec.keyFromPrivate(keyPair.secretKey.value.toHex, "hex") }("Cannot get private key from key pair.") hash ← hash(message) - signHex ← nonFatalHandling(secret.sign(hash).toDER("hex"))("Cannot sign message") + signHex ← nonFatalHandling(secret.sign(new Uint8Array(hash)).toDER("hex"))("Cannot sign message") } yield Signature(keyPair.publicKey, ByteVector.fromValidHex(signHex)) } @@ -78,7 +79,7 @@ class Ecdsa(ec: EC, hasher: Option[CryptoHasher[Array[Byte], Array[Byte]]]) ec.keyFromPublic(hex, "hex") }("Incorrect public key format.") hash ← hash(message) - verify ← nonFatalHandling(public.verify(hash, signature.sign.toHex))("Cannot verify message.") + verify ← nonFatalHandling(public.verify(new Uint8Array(hash), signature.sign.toHex))("Cannot verify message.") _ ← EitherT.cond[F](verify, (), CryptoErr("Signature is not verified")) } yield () } diff --git a/js/src/main/scala/fluence/crypto/facade/ecdsa/Elliptic.scala b/js/src/main/scala/fluence/crypto/facade/ecdsa/Elliptic.scala index 96bf4b3..9938af7 100644 --- a/js/src/main/scala/fluence/crypto/facade/ecdsa/Elliptic.scala +++ b/js/src/main/scala/fluence/crypto/facade/ecdsa/Elliptic.scala @@ -19,6 +19,7 @@ package fluence.crypto.facade.ecdsa import scala.scalajs.js import scala.scalajs.js.annotation._ +import scala.scalajs.js.typedarray.Uint8Array //TODO hide enc argument in methods, make it `hex` by default /** @@ -36,8 +37,8 @@ class EC(curve: String) extends js.Object { @js.native @JSImport("elliptic", "ec") class KeyPair(ec: EC, options: js.Dynamic) extends js.Object { - def verify(msg: js.Array[Byte], signature: String): Boolean = js.native - def sign(msg: js.Array[Byte]): Signature = js.native + def verify(msg: Uint8Array, signature: String): Boolean = js.native + def sign(msg: Uint8Array): Signature = js.native def getPublic(compact: Boolean, enc: String): String = js.native def getPrivate(enc: String): String = js.native diff --git a/js/src/main/scala/fluence/crypto/facade/ecdsa/Hash.scala b/js/src/main/scala/fluence/crypto/facade/ecdsa/Hash.scala index 8ad9503..5ede6d4 100644 --- a/js/src/main/scala/fluence/crypto/facade/ecdsa/Hash.scala +++ b/js/src/main/scala/fluence/crypto/facade/ecdsa/Hash.scala @@ -19,6 +19,7 @@ package fluence.crypto.facade.ecdsa import scala.scalajs.js import scala.scalajs.js.annotation.JSImport +import scala.scalajs.js.typedarray.Uint8Array //TODO hide enc argument in methods, make it `hex` by default /** @@ -27,13 +28,13 @@ import scala.scalajs.js.annotation.JSImport @js.native @JSImport("hash.js", "sha256") class SHA256() extends js.Object { - def update(msg: js.Array[Byte]): Unit = js.native + def update(msg: Uint8Array): Unit = js.native def digest(enc: String): String = js.native } @js.native @JSImport("hash.js", "sha1") class SHA1() extends js.Object { - def update(msg: js.Array[Byte]): Unit = js.native + def update(msg: Uint8Array): Unit = js.native def digest(enc: String): String = js.native } diff --git a/js/src/main/scala/fluence/crypto/hash/JsCryptoHasher.scala b/js/src/main/scala/fluence/crypto/hash/JsCryptoHasher.scala index 1434b46..bfb8adb 100644 --- a/js/src/main/scala/fluence/crypto/hash/JsCryptoHasher.scala +++ b/js/src/main/scala/fluence/crypto/hash/JsCryptoHasher.scala @@ -21,20 +21,21 @@ import fluence.crypto.facade.ecdsa.{SHA1, SHA256} import scodec.bits.ByteVector import scala.scalajs.js.JSConverters._ +import scala.scalajs.js.typedarray.Uint8Array object JsCryptoHasher { lazy val Sha256: CryptoHasher.Bytes = CryptoHasher.buildM[Array[Byte], Array[Byte]] { msg ⇒ val sha256 = new SHA256() - sha256.update(msg.toJSArray) + sha256.update(new Uint8Array(msg.toJSArray)) ByteVector.fromValidHex(sha256.digest("hex")).toArray }(_ ++ _) lazy val Sha1: CryptoHasher.Bytes = CryptoHasher.buildM[Array[Byte], Array[Byte]] { msg ⇒ val sha1 = new SHA1() - sha1.update(msg.toJSArray) + sha1.update(new Uint8Array(msg.toJSArray)) ByteVector.fromValidHex(sha1.digest("hex")).toArray }(_ ++ _) } diff --git a/js/src/test/scala/fluence/crypto/JSHashSpec.scala b/js/src/test/scala/fluence/crypto/JSHashSpec.scala index 7fc499c..98be79a 100644 --- a/js/src/test/scala/fluence/crypto/JSHashSpec.scala +++ b/js/src/test/scala/fluence/crypto/JSHashSpec.scala @@ -19,8 +19,10 @@ package fluence.crypto import fluence.crypto.facade.ecdsa.{SHA1, SHA256} import org.scalatest.{Matchers, WordSpec} +import scodec.bits.{Bases, ByteVector} import scala.scalajs.js.JSConverters._ +import scala.scalajs.js.typedarray.Uint8Array class JSHashSpec extends WordSpec with Matchers { "js hasher" should { @@ -30,7 +32,7 @@ class JSHashSpec extends WordSpec with Matchers { val sha256TesterHex = "513c17f8cf6ba96ce412cc2ae82f68821e9a2c6ae7a2fb1f5e46d08c387c8e65" val hasher = new SHA256() - hasher.update(str.getBytes().toJSArray) + hasher.update(new Uint8Array(str.getBytes().toJSArray)) val hex = hasher.digest("hex") hex shouldBe sha256TesterHex } @@ -40,9 +42,23 @@ class JSHashSpec extends WordSpec with Matchers { val sha1TesterHex = "879db20eabcecea7d4736a8bae5bc64564b76b2f" val hasher = new SHA1() - hasher.update(str.getBytes().toJSArray) + hasher.update(new Uint8Array(str.getBytes().toJSArray)) val hex = hasher.digest("hex") hex shouldBe sha1TesterHex } + + "check unsigned array with sha1" in { + + val arr = Array[Byte](3, -9, -31, 48, 10, 125, 51, -39, -20, -125, 123, 61, -36, 49, 76, 90, -16, 54, -61, 62, 50, + -116, -37, -88, -125, -32, -105, 120, 118, 13, -37, 33, -36) + + val base64Check = "9keNwsj08vKTlwIpHAEYvsfpdP4=" + + val hasher = new SHA1() + hasher.update(new Uint8Array(arr.toJSArray)) + val hex = hasher.digest("hex") + + ByteVector.fromValidHex(hex, Bases.Alphabets.HexLowercase).toBase64 shouldBe base64Check + } } } diff --git a/jvm/src/test/scala/fluence/crypto/JvmHashSpec.scala b/jvm/src/test/scala/fluence/crypto/JvmHashSpec.scala index c6218b1..f56f6ee 100644 --- a/jvm/src/test/scala/fluence/crypto/JvmHashSpec.scala +++ b/jvm/src/test/scala/fluence/crypto/JvmHashSpec.scala @@ -39,5 +39,17 @@ class JvmHashSpec extends WordSpec with Matchers { val hasher = JdkCryptoHasher.Sha1 ByteVector(hasher.hash(str.getBytes())).toHex shouldBe sha1TesterHex } + + "check unsigned array with sha1" in { + + val arr = Array[Byte](3, -9, -31, 48, 10, 125, 51, -39, -20, -125, 123, 61, -36, 49, 76, 90, -16, 54, -61, 62, 50, + -116, -37, -88, -125, -32, -105, 120, 118, 13, -37, 33, -36) + + val base64Check = "9keNwsj08vKTlwIpHAEYvsfpdP4=" + + val hasher = JdkCryptoHasher.Sha1 + + ByteVector(hasher.hash(arr)).toBase64 shouldBe base64Check + } } }