tinygo icon indicating copy to clipboard operation
tinygo copied to clipboard

Lacking RSA keypair capacity in Tinygo

Open lewiseliu opened this issue 3 years ago • 6 comments
trafficstars

Hi community,

Seems no crypto/cipher package in Tinygo, which is availabe in standard Golang. If so, seems we can not achieve Sign and Check feature of RSA private / public key pair with Tinygo in our WASM proxy project for proxy Envoy.

Anybody who can help to advise the workaround solution will be appreciated?

lewiseliu avatar Sep 04 '22 04:09 lewiseliu

TinyGo uses the Go standard library for most packages, so crypto/rsa is available. But it might not work yet because some things might not be implemented.

Can you share the error you're getting?

aykevl avatar Sep 04 '22 11:09 aykevl

I think crypto/cipher has some issues with dispatching to the specialized xorBytes implementations, or at least it did once upon a time.

dgryski avatar Sep 04 '22 17:09 dgryski

@aykevl, @deadprogram @dgryski we are doing the coding. The time being, we found crypto/rsa is able to be imported but can not pass test, on this page https://tinygo.org/docs/reference/lang-support/stdlib/#crypto.

We are confused:

  1. what is the meaning of yes on importable but no on passes tests?
  2. Does it means the runtime functionality still not work even though no compile error?

lewiseliu avatar Sep 09 '22 14:09 lewiseliu

Today we have a validation on the support capacity on crypto/rsa with Tinygo. Unfortunately, as the official support description, Crypto/rsa is not supported well.

Below exception will be feed back with tinygo, while it works well with Golang.

tinygo build -o test.exe .\examples\main.go

ld.lld: error: undefined symbol: crypto/ed25519/internal/edwards25519/field.feMul
>>> referenced by main
>>>               C:\Users\lewise.liu\AppData\Local\Temp\tinygo3568153588\main.o

ld.lld: error: undefined symbol: crypto/ed25519/internal/edwards25519/field.feSquare
>>> referenced by main
>>>               C:\Users\lewise.liu\AppData\Local\Temp\tinygo3568153588\main.o
failed to run tool: ld.lld
error: failed to link C:\Users\lewise.liu\AppData\Local\Temp\tinygo3568153588\main.exe: exit status 1

The source code as below: https://github.com/vspaz/rsa-encrypt-decrypt-golang/

package cryptolib

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/ascii85"
	"encoding/base64"
	"encoding/pem"
	"log"
)

type Encoder struct {
	PublicKeyBlock *pem.Block
}

func NewEncoder(publicKey string) *Encoder {
	publicKeyBlock, _ := pem.Decode([]byte(publicKey))
	return &Encoder{
		PublicKeyBlock: publicKeyBlock,
	}
}

func (e *Encoder) Encrypt(text string) []byte {
	encodedText := []byte(text)
	var rsaPublicKey *rsa.PublicKey
	pub, err := x509.ParsePKIXPublicKey(e.PublicKeyBlock.Bytes)
	if err != nil {
		log.Fatal("Failed to load public key")
	}
	rsaPublicKey = pub.(*rsa.PublicKey)
	encryptedText, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, rsaPublicKey, encodedText, nil)
	if err != nil {
		log.Fatal("Failed to encrypt text with public key")
	}
	return encryptedText
}

func (e Encoder) ToBase85(text []byte) string {
	dest := make([]byte, ascii85.MaxEncodedLen(len(text)))
	ascii85.Encode(dest, text)
	return string(dest)
}

func (e Encoder) ToBase64(text []byte) string {
	return base64.StdEncoding.EncodeToString(text)
}

lewiseliu avatar Sep 12 '22 13:09 lewiseliu

I'll try to take a look into this.

dgryski avatar Sep 12 '22 16:09 dgryski

After some patching to get the tests building under tinygo:

~/go/src/github.com/vspaz/rsa-encrypt-decrypt-golang/pkg/cryptolib $ tinygo test -target=wasi
panic: unimplemented: (reflect.Value).Addr()
Error: failed to run main module `/var/folders/5b/_hr1d1fd3qn4t9vtfx5p61wm0000gp/T/tinygo3346914303/main`

Caused by:
    0: failed to invoke command default
    1: wasm trap: wasm `unreachable` instruction executed
       wasm backtrace:
           0: 0x1efe - <unknown>!runtime._panic
           1: 0x5441 - <unknown>!(reflect.Value).Addr
           2: 0x777e7 - <unknown>!encoding/asn1.Unmarshal
           3: 0xa8948 - <unknown>!(*github.com/vspaz/rsa-encrypt-decrypt-golang/pkg/cryptolib.Encoder).Encrypt
           4: 0xac149 - <unknown>!github.com/vspaz/rsa-encrypt-decrypt-golang/pkg/cryptolib.TestRsaEncryptDecrypt

So, this is more reflect work. The link errors you observed are due to native (amd64) builds having the amd46 build tag but not (yet!) supporting the assembly routines. When built for wasi, we get the reflect issue above.

dgryski avatar Sep 12 '22 23:09 dgryski

This works now, only required patching the tests to avoid the use of testify:

~/go/src/github.com/vspaz/rsa-encrypt-decrypt-golang/pkg/cryptolib $ tinygo test  -target=wasi
ok  	github.com/vspaz/rsa-encrypt-decrypt-golang/pkg/cryptolib	0.482s
~/go/src/github.com/vspaz/rsa-encrypt-decrypt-golang/pkg/cryptolib $ git diff
diff --git a/pkg/cryptolib/encoding_decoding_test.go b/pkg/cryptolib/encoding_decoding_test.go
index b417d26..efcd02e 100644
--- a/pkg/cryptolib/encoding_decoding_test.go
+++ b/pkg/cryptolib/encoding_decoding_test.go
@@ -1,10 +1,15 @@
 package cryptolib

 import (
-       "github.com/stretchr/testify/assert"
        "testing"
 )

+func assertEqual(t *testing.T, a, b string) {
+       if a != b {
+               t.Errorf("assertEqual failed: got %v, want %v", a, b)
+       }
+}
+

dgryski avatar Mar 23 '23 05:03 dgryski

This is part of the v0.28 release so now closing this issue. Thanks!

deadprogram avatar Jun 14 '23 08:06 deadprogram