Use RSA between android and go

Viewed 4083

In a chat project with go and android, I want to use RSA for encryption

I found solution in this question, and work find, but i need to change private and public key for each user !

How can i create private and public key in go for sending to android ?

I try many ways but in android give error when i want parse public key Android

    public static PublicKey stringToPublicKeytoserver(String publicKeyString)
    {
        try {
            publicKeyString = publicKeyString.replace("-----BEGIN PUBLIC KEY-----", "");
            publicKeyString = publicKeyString.replace("-----END PUBLIC KEY-----", "");
            byte[] keyBytes = Base64.decode(publicKeyString, Base64.DEFAULT);
            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            serveruk=keyFactory.generatePublic(spec);
            return serveruk;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
            return null;
        }
    }

Android Error

java.security.spec.InvalidKeySpecException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: Error parsing public key

Key Generation

   // Generate RSA Keys
   miryanPrivateKey, err := rsa.GenerateKey(rand.Reader, 1024)
   fatal(err)


   // save PEM file
   pemfile, err := os.Create("public.pem")

   if err != nil {
       fmt.Println(err)
       os.Exit(1)
   }

   //publi := &miryanPrivateKey.PublicKey

   // http://golang.org/pkg/encoding/pem/#Block

   var pemkey = &pem.Block{
       Type : "PUBLIC KEY",
       Bytes : x509.MarshalPKCS1PublicKey(&miryanPrivateKey.PublicKey)}

   err = pem.Encode(pemfile, pemkey)

   if err != nil {
       fmt.Println(err)
       os.Exit(1)
   }

   pemfile.Close()
   //and even i use function to convert toPKCS8
   byt, _:= MarshalPKCS8PublicKey(&miryanPrivateKey.PublicKey)

   var pemkey = &pem.Block{
       Type : "PUBLIC KEY",
       Bytes : byt}

   func MarshalPKCS8PublicKey(key *rsa.PublicKey) ([]byte, error) {
   var pkey PKCS8Key
   pkey.Version = 0
   pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
   pkey.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
   pkey.PrivateKey = x509.MarshalPKCS1PublicKey(key)
   return asn1.Marshal(pkey)
}

i think my main problem is, go use pkcs1 but android use pkcs8

public.pem

-----BEGIN PUBLIC KEY-----
MIGfAgEAMAsGCSqGSIb3DQEBAQSBjDCBiQKBgQDh1jHGdbo/QLeA1y5lC2YSSoal
hPBLWxz7OYpNj5pZDcuqrJFfhEvv1CGvBR0bKB/3hTpUYAPiswI+OH2BcHks0+Ef
N/KZYjPQQsB1gJByENTPvdQwlDIJVW8cDhij7jMMwq/TOs+ijudCUojcfvkJ5Zvf
BJB6g0ucg580W98K4wIDAQAB
-----END PUBLIC KEY-----
1 Answers

I fix it !

I generate public and private key with this Go code :

/*
 * Genarate rsa keys.
*/

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/gob"
    "encoding/pem"
    "fmt"
    "os"
)

func main() {
    reader := rand.Reader
    bitSize := 2048

    key, err := rsa.GenerateKey(reader, bitSize)
    checkError(err)

    publicKey := key.PublicKey

    saveGobKey("private.key", key)
    savePEMKey("private.pem", key)

    saveGobKey("public.key", publicKey)
    savePublicPEMKey("public.pem", publicKey)
}

func saveGobKey(fileName string, key interface{}) {
    outFile, err := os.Create(fileName)
    checkError(err)
    defer outFile.Close()

    encoder := gob.NewEncoder(outFile)
    err = encoder.Encode(key)
    checkError(err)
}

func savePEMKey(fileName string, key *rsa.PrivateKey) {
    outFile, err := os.Create(fileName)
    checkError(err)
    defer outFile.Close()

    var privateKey = &pem.Block{
        Type:  "PRIVATE KEY",
        Bytes: x509.MarshalPKCS1PrivateKey(key),
    }

    err = pem.Encode(outFile, privateKey)
    checkError(err)
}

func savePublicPEMKey(fileName string, pubkey rsa.PublicKey) {
    asn1Bytes, err := x509.MarshalPKIXPublicKey(&pubkey)
    checkError(err)

    var pemkey = &pem.Block{
        Type:  "PUBLIC KEY",
        Bytes: asn1Bytes,
    }

    pemfile, err := os.Create(fileName)
    checkError(err)
    defer pemfile.Close()

    err = pem.Encode(pemfile, pemkey)
    checkError(err)
}

func checkError(err error) {
    if err != nil {
        fmt.Println("Fatal error ", err.Error())
        os.Exit(1)
    }
}

and then i encrypt my message in android with generated public key in GO:

static PublicKey serveruk;


public final static String chi="RSA/ECB/OAEPPadding";

public final static String RSA = "RSA";

private final static int CRYPTO_BITS = 512;


String pubPEM = "public key from public.pem";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    stringToPublicKeytoserver(pubPEM);
    Log.e("ENCODED", enc4golang("Please hide me !"));

}


public static PublicKey stringToPublicKeytoserver(String publicKeyString)
{
    try {
        publicKeyString = publicKeyString.replace("-----BEGIN PUBLIC KEY-----", "");
        publicKeyString = publicKeyString.replace("-----END PUBLIC KEY-----", "");
        byte[] keyBytes = Base64.decode(publicKeyString, Base64.DEFAULT);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        serveruk=keyFactory.generatePublic(spec);
        return serveruk;
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
        e.printStackTrace();
        return null;
    }
}


private static byte[] enc4golang(String text, PublicKey pubRSA) throws Exception{
    Cipher cipher = Cipher.getInstance(chi);
    cipher.init(Cipher.ENCRYPT_MODE, pubRSA);
    return cipher.doFinal(text.getBytes("UTF-8")); //i also advice you to use: .getBytes("UTF-8"); instead of data.getBytes();
}


public final static String enc4golang(String text){
    try {
        return Base64.encodeToString(enc4golang(text, serveruk) ,Base64.DEFAULT);  //send this string to golang
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    return null;
}

and then i decrypt it with this GO code:

package main

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

func main(){

    const priPEM = `private key from private.pem`

    const pubPEM = `public key from public.pem`

    base64DecodeBytes, err := base64.StdEncoding.DecodeString("encrypted data from android")
    if err != nil {
        panic(err)
    }
    privateKeyBlock, _ := pem.Decode([]byte(priPEM))
    var pri *rsa.PrivateKey
    pri, parseErr := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes)
    if parseErr != nil {
        panic(parseErr)
    }
    decryptedData, decryptErr := rsa.DecryptOAEP(sha1.New(), rand.Reader, pri, base64DecodeBytes, nil)
    if decryptErr != nil {
        panic(decryptErr)
    }

    print(string(decryptedData))

}
Related