1

My attempt with String::from_utf8 returns an error:

fn main() {
    let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
    let pair = PKey::from_ec_key(EcKey::generate(&group).unwrap()).unwrap();
    println!(
        "Public: {:?}",
        String::from_utf8(pair.public_key_to_pem().unwrap())
    );
    println!(
        "Private: {:?}",
        String::from_utf8(pair.private_key_to_pem_pkcs8().unwrap())
    );

    let data = b"hello";

    let mut signer = Signer::new(MessageDigest::sha512(), &pair).unwrap();
    signer.update(data).unwrap();

    let signature = signer.sign_to_vec().unwrap();

    println!("Signature: {:?}", String::from_utf8(signature));
}
Public: Ok("-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n")
Private: Ok("-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n")
Signature: Err(FromUtf8Error { bytes: [48, 69, 2, 33, 0, 221, 124, 107, 80, 118, 244, 208, 146, 83, 198, 12, 244, 45, 218, 184, 160, 152, 119, 117, 176, 124, 209, 252, 115, 173, 49, 31, 84, 247, 201, 187, 233, 2, 32, 1, 126, 10, 149, 78, 239, 13, 110, 84, 60, 81, 111, 252, 195, 246, 214, 176, 157, 116, 65, 125, 75, 66, 164, 207, 110, 141, 203, 85, 60, 111, 126], error: Utf8Error { valid_up_to: 5, error_len: Some(1) } })

How can I get the signature as a String?

kmdreko
  • 42,554
  • 6
  • 57
  • 106
Nikk
  • 7,384
  • 8
  • 44
  • 90
  • 2
    the signature is not a valid utf-8 sequence of bytes but an arbitrary sequence of bytes; it cannot be considered as a string. – prog-fh Sep 14 '22 at 11:55
  • See here: https://stackoverflow.com/questions/10782826/digital-signature-for-a-file-using-openssl This demonstrates how to create these things from command line. Note, as mentioned in one of the comments, that the signature is **not** human readable text, but instead binary data. So you have to treat it as such, you cannot load it into a String object. It should remain a `Vec`. – Finomnis Sep 14 '22 at 12:53
  • Similar to `PEM` you could also base64-encode it – peterulb Sep 14 '22 at 12:59

1 Answers1

2

The public and private keys are here represented in the PEM format, which is human readable and therefore storable in a String.

The signature, however, gets returned as raw binary data. It is not human readable and therefore not directly storable in a string.

If you still want to store it in a string, you have to convert it into a human readable encoding, like base64:

use openssl::{
    ec::{EcGroup, EcKey},
    hash::MessageDigest,
    nid::Nid,
    pkey::PKey,
    sign::Signer,
};

fn main() {
    let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
    let pair = PKey::from_ec_key(EcKey::generate(&group).unwrap()).unwrap();
    println!(
        "Public:\n{}\n",
        String::from_utf8(pair.public_key_to_pem().unwrap()).unwrap()
    );
    println!(
        "Private:\n{}\n",
        String::from_utf8(pair.private_key_to_pem_pkcs8().unwrap()).unwrap()
    );

    let data = b"hello";

    let mut signer = Signer::new(MessageDigest::sha512(), &pair).unwrap();
    signer.update(data).unwrap();

    let signature = signer.sign_to_vec().unwrap();

    let signature_base64 = base64::encode(signature);

    println!("Signature:\n{}\n", signature_base64);
}
Public:
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEfC8hXiKyuS2U/Kcg+HQuKYA+29wYZeGj
lOSTeMhj7xTqktPrCONJg1Acb1rjqU4kNdMEzUMwKemoqT0OWe/5yw==
-----END PUBLIC KEY-----


Private:
-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQg64c0IelDNgh9MsROvoGQ
TCUMbklvGtWF1RcLhsdLefmhRANCAAR8LyFeIrK5LZT8pyD4dC4pgD7b3Bhl4aOU
5JN4yGPvFOqS0+sI40mDUBxvWuOpTiQ10wTNQzAp6aipPQ5Z7/nL
-----END PRIVATE KEY-----


Signature:
MEUCIEnP49eZTk6y624A+FPCLIWNEpkZMj82QOu99BFi6r/tAiEA7ThuWNF/j5hTSw8N2MNOv1D3fU4a7ThYz1cu/jQJNrk=

Note that if you want to use it for verification later, you have to convert the base64 encoded string back to its raw representation.

Finomnis
  • 18,094
  • 1
  • 20
  • 27