Can't DER encode and BER decode RSA public key - public-key

I have problems using Crypto++ to save a RSA public key (that I obtained loading a private key file in PKCS#8 format). When decoding the key, I always get a BERDecodeErr exception.
Here is the code I am using:
CryptoPP::RSASSA_PKCS1v15_SHA_Signer _signer;
CryptoPP::RSASSA_PKCS1v15_SHA_Verifier _verifier;
CryptoPP::ByteQueue bytes;
//_signer.AccessPublicKey().Save(bytes); // seem to save private key instead
_signer.AccessKey().DEREncodePublicKey(bytes);
//_verifier.AccessKey().Load(bytes);
//_verifier.AccessKey().BERDecodePublicKey(bytes, 0, 0);
_verifier.AccessPublicKey().Load(bytes);
I also tried with the instructions commented above, without success.
How do you do to save or open the public key?
The public key looks like this in hex format, is there a tool to check its format / validity (regarding what crypto++ supports) ?
3081890281810097e24f2e95504a397e90fbc56d1b330ab2ab97a0d326007b890e40013f9e1d9bd9
f54b0c0840782ddae19b5b4595d8f8b9ffe0d2120174fcbc39585c5867cd2dfba69f8e540caa2c52
de8f08278a34e9249120500117f0ba756c5bb2be660013160db9f82f75deb7ccf63742a9e945da6c
cf30c2b109b73342daaabd02b872e50203010001

I'm not sure I understand your problem completely. But you look like you are on the right track with using either Load/Save or BERDecodePublicKey/DEREncodePublicKey.
Here's how I would approach it given you have a PKCS#8 encoded private key.
FileSource privateKey("<private key>", true);
RSASSA_PKCS1v15_SHA_Signer signer;
signer.AccessKey().Load(privateKey);
AutoSeededRandomPool prng;
bool valid = signer.AccessKey().Validate(prng, 3);
...
RSASSA_PKCS1v15_SHA_Verifier verifier(signer);
FileSink publicKey("<public key>", true);
verifier.AccessKey().Save(publicKey);
Then, you can use Gutmann's dumpasn1 to print it:
$ dumpasn1 <public key>
...
I believe you can also convert a private key/signer to a public key/verifier with:
RSASSA_PKCS1v15_SHA_Signer signer;
signer.AccessKey().Load(privateKey);
RSASSA_PKCS1v15_SHA_Verifier verifier;
signer.MakePublic(verifier);
There's also a page on the Crypto++ wiki that talks about it in greater detail: Keys and Formats. And there's a page dedicated to PEM encoding, if interested: PEM Pack. If you want the PEM encoding, you have to compile the library yourself, though.
Here's the code I used with the public key you posted. It had no problems.
string key = "3081890281810097e24f2e95504a397e90fbc56d1b330ab2ab97a0d326007b890e40013f9e1d9bd9 \
f54b0c0840782ddae19b5b4595d8f8b9ffe0d2120174fcbc39585c5867cd2dfba69f8e540caa2c52 \
de8f08278a34e9249120500117f0ba756c5bb2be660013160db9f82f75deb7ccf63742a9e945da6c \
cf30c2b109b73342daaabd02b872e50203010001";
ByteQueue queue;
StringSource ss(key, true, new HexDecoder(new Redirector(queue)));
RSASSA_PKCS1v15_SHA_Verifier verifier;
verifier.AccessKey().BERDecodePublicKey(queue, false, 0);
AutoSeededRandomPool prng;
bool result = verifier.AccessKey().Validate(prng, 3);
if(!result)
throw Exception(Exception::OTHER_ERROR, "Failed to validate public key");
If you install the PEM Pack then you can add the following:
FileSink sink("public-key.pem", true);
PEM_Save(sink, verifier.GetKey());
That will get you:
$ cat public-key.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCX4k8ulVBKOX6Q+8VtGzMKsquX
oNMmAHuJDkABP54dm9n1SwwIQHgt2uGbW0WV2Pi5/+DSEgF0/Lw5WFxYZ80t+6af
jlQMqixS3o8IJ4o06SSRIFABF/C6dWxbsr5mABMWDbn4L3Xet8z2N0Kp6UXabM8w
wrEJtzNC2qq9Arhy5QIDAQAB
-----END PUBLIC KEY-----
And:
$ openssl rsa -in public-key.pem -pubin -text -noout
Public-Key: (1024 bit)
Modulus:
00:97:e2:4f:2e:95:50:4a:39:7e:90:fb:c5:6d:1b:
33:0a:b2:ab:97:a0:d3:26:00:7b:89:0e:40:01:3f:
9e:1d:9b:d9:f5:4b:0c:08:40:78:2d:da:e1:9b:5b:
45:95:d8:f8:b9:ff:e0:d2:12:01:74:fc:bc:39:58:
5c:58:67:cd:2d:fb:a6:9f:8e:54:0c:aa:2c:52:de:
8f:08:27:8a:34:e9:24:91:20:50:01:17:f0:ba:75:
6c:5b:b2:be:66:00:13:16:0d:b9:f8:2f:75:de:b7:
cc:f6:37:42:a9:e9:45:da:6c:cf:30:c2:b1:09:b7:
33:42:da:aa:bd:02:b8:72:e5
Exponent: 65537 (0x10001)
Finally, the difference between:
verifier.AccessKey(): gets the RSA::Public key, the key is non-const
verifier.GetKey(): gets the RSA::Public key, the key is const

Related

Get readable format from public key

I have o convert an public key in redable format.
I have this public key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3qRkBn/pouirEVL/H+at
FLbB1Wmm41Y/4REbuNwMkPNGHhTwVNF4mSvUFdK6L0SYZ8f8B1oe6YzfZ+bWBAde
oiupY6ABHJ8xGkb14RBwFm152kUT29jXXKU9N8aKGsWayOO7ZLIMOnFrWrjIrrLa
NSkKfuCxywOInjcpkuaq/c+cdxKIDTw1QsUrz3rN1s/TJsvfY+oeFtzCh1auE2dQ
dVPxSeK1ApMsXsXfUP85UNloGlruSrf2IyxK33trNGigH2qD/1PHcjft8PiG00gD
9R2DR0bBASpz/CYKEm6Ry37lVJif0OtQKnyVTap4yLuWaMlZiFaSfBh0FlueHLxN
QwIDAQAB
-----END PUBLIC KEY-----
I wanted extract JWK from this public key like this
{
"kty": "RSA",
"n": "3FCW9xBBsviZUQnDlcZczC_GO0J0Vhzx1VUj_JyM8hTBzJ_--1GHH5k60OHz169jEHgJ9kkwIKP0ld8Ah5-6x1z5a_Vh-uFizbPn45MgUjwuEL2VPeZsn_wPb2t-A6otOR5zUNU_n4xXcjqZETpvEjFQFQ2n_SDujZUMtQfda9f_plTaekqws4iWIr2sA4QNXXSvv6JvWmjp49N6AQexrVRW9XFBkEFpqofwdWkJMU9TJThzzZB--GA8f4CHfD_DsX_aOsM1u1oCmjWiKmz793NhDQChY0LApEjosTm9a0kQuYEEfGrLNiLfplIsXq6Qw4lFCiWDv553J4_nJusAsw",
"e": "AQAB",
"alg": "RS256",
"use": "sig"
}
How can i covert this public key and get JWK using terminal or any other tool.
You can use authlib library + python3
https://authlib.org/
from authlib.jose import jwk
rsa_key={
'public_key':'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3qRkBn/pouirEVL/H+at\nFLbB1Wmm41Y/4REbuNwMkPNGHhTwVNF4mSvUFdK6L0SYZ8f8B1oe6YzfZ+bWBAde\noiupY6ABHJ8xGkb14RBwFm152kUT29jXXKU9N8aKGsWayOO7ZLIMOnFrWrjIrrLa\nNSkKfuCxywOInjcpkuaq/c+cdxKIDTw1QsUrz3rN1s/TJsvfY+oeFtzCh1auE2dQ\ndVPxSeK1ApMsXsXfUP85UNloGlruSrf2IyxK33trNGigH2qD/1PHcjft8PiG00gD\n9R2DR0bBASpz/CYKEm6Ry37lVJif0OtQKnyVTap4yLuWaMlZiFaSfBh0FlueHLxN\nQwIDAQAB\n-----END PUBLIC KEY-----'
}
print(jwk.dumps(rsa_key['public_key'], kty='RSA'))
notice there is a \n at end of each line of the key
If you are using C# then the following here solution could be helpful for you.

ganache-cli how to read private key from account json file

I am running ganache-cli through a node application:
const ganache = require('ganache-core');
const ethers = require('ethers');
const provider = new ethers.providers.Web3Provider(
ganache.provider({
total_accounts: 5,
account_keys_path: './accounts.json',
gasPrice: 20000000000,
gasLimit: 20000000000,
default_balance_ether: 100
})
);
This runs the ganache-cli and output acocunt details in accounts.json. The file looks like this:
{
"addresses":{
"0x73f5b3f74db1b37927696c280c04d544f4e9ff64":{
"secretKey":{
"type":"Buffer",
"data":[88, 17, .....]
},
"publicKey":{
"type":"Buffer",
"data":[13, 52, .....]
},
"address":"0x73f5b3f74db1b37927696c280c04d544f4e9ff64",
"account":{
"nonce":"0x",
"balance":"0x056bc75e2d63100000",
"stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
}
}
}
}
I can see the account address, but how can I decode/get the private key from this information?
You cannot get the private key from accounts directly, but there's a few workarounds to do this with ganache-cli.
Specify a mnemonic phrase with the -m option, e.g. ganache-cli -m "stereo consider quality wild fat farm symptom bundle laundry side one lemon", this will derive private keys from the mnemonic phrase (with the derivation path m/44'/60'/0'/0/n.
Use the --account_keys_path option to save all private keys to a file, e.g. ganache-cli --account_keys_path keys.json. This will result in a JSON file with all addresses, private keys and public keys.
Use the --account option to manually specify a private key and balance, e.g. ganache-cli --account "0x31c354f57fc542eba2c56699286723e94f7bd02a4891a0a7f68566c2a2df6795,1000000000000000000". This will assign 1 ETH (= 1000000000000000000 Wei) to the address corresponding to this private key. You can use the --account option multiple times, with different private keys.

getting "SyntaxError:" Unexpected token in JSON at position 0 at JSON.parse"

getting "SyntaxError:" Unexpected token in JSON at position 0 at JSON.parse" on fetching data from backend spring boot compressed as gzip in Angular 7
In backend I'm compressing the list of objects as follows:
ArticleObj.java
public class ArticleObj{
private String id;
private String name;
private String heading;
private String language;
private String identifier1;
private String identifier2;
private String identifier3;
private String identifier4;
private String identifier5;
private String identifier6;
private String identifier7;
private String identifier8;
private String identifier9;
private String identifier10;
private String baseIndentifier;
private String moduleId;
.....
...
}
// size of the list is around 5000-6000
List<ArticleObj> tempList=new ArrayList<ArticleObj>();
String json=new Gson().toJson(tempList);
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(out);
gzip.write(json.getBytes());
gzip.close();
String outStr = out.toString("UTF-8");
In Angular, I'm this is what I'm trying
getData(){
const headers = new HttpHeaders({
"Accept-Encoding": "gzip", "Content-Type":"application/json"
})
return this.http.get(url,{headers:headers});
}
this.getData().subscribe(res=> ....)
I don't know how to decompress the gzip data into json in angular. The reason I'm compressing the list into gzip is because the size of the list is more than 20mb and is taking lot of time in angular to consume that data. Can anyone please help me our here.
Instead of sending a zip file from the back-end you should send the JSON and use gzip compression. Browsers have built-in support for gzip compressed HTTP responses and will automatically unzip the contents. In this way you won't have to handle unzipping yourself and you can just use the JSON body.
Keep in mind that gzip will speed up the time spent to download the resource but will take additional CPU resources to decompress the archive.
#Tsvetav Ganev, thank you very much for pointing me in the right direction. I did what you said and sent my response as JSON and implemented spring boot gzip compression using
server.compression.enabled=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
server.compression.min-response-size=2KB (2kb is default min size)
in application.properties file.
Now the response time is almost 80% reduced.

JSON Web Signature (Ninbus-JOSE-JWT)

I want to do a project with JSON Web Signature (JWS) and i want to send the public key of the certificate used for the signature so that the message can be validated once received with this public key. I am using the Ninbus JOS JWT library. I can sign the JSON object and I can see the public key, but i can not validate it correctly.
This is the code:
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(_signatureKey_); // PrivateKey
com.nimbusds.jose.util.Base64 b64 = new com.nimbusds.jose.util.Base64(_x509certificate.toString()); // X509Certificate
ArrayList<com.nimbusds.jose.util.Base64> certificados = new ArrayList<com.nimbusds.jose.util.Base64>();
certificados.add(b64);
RSAPublicKey _rsaPublicKey = (RSAPublicKey)_x509certificate.getPublicKey(); // Get the public key of the X509Certificate
RSAKey jwk = new com.nimbusds.jose.jwk.RSAKey.Builder( new Base64URL( _rsaPublicKey.getModulus().toString()), new Base64URL( _rsaPublicKey.getPublicExponent().toString()))
.x509CertChain(certificados)
.build();
JWSHeader _jwsHeader = new JWSHeader.Builder(JWSAlgorithm.RS256).
x509CertChain(certificados).
jwk(jwk).
build();
// Prepare JWS object with simple string as payload
JWSObject jwsObject = new JWSObject(_jwsHeader, new Payload(_jsonObject));
// Compute the RSA signature
jwsObject.sign(signer);
// Validation OK : This validation works
JWSVerifier verifier = new RSASSAVerifier(_rsaPublicKey);
boolean signatureValid = jwsObject.verify(verifier); // ---> True, OK
// Now I want to validate the JWSObject getting the public key from the same JWSObject. This validation Fails
JWK _jwk = jwsObject.getHeader().getJWK();
RSAKey _rsakey = (RSAKey)_jwk;
RSAPublicKey _rsaPublicKey2 = _rsakey.toRSAPublicKey();
JWSVerifier verifier2 = new RSASSAVerifier(_rsakey.toRSAPublicKey());
boolean verificado2 = jwsObject.verify(verifier2); // False!
// Another option, this fails too
RSAKey __rsaKey2 = new com.nimbusds.jose.jwk.RSAKey.Builder( _rsakey.toRSAPublicKey() ).x509CertChain(_jwk.getX509CertChain()).build();
JWSVerifier verifier3 = new RSASSAVerifier(__rsaKey2);
boolean verificado3 = jwsObject.verify(verifier3); // False!
The _rsaPublicKey is: "Sun RSA public key, 2048 bits", but when i get it from the JWK (_rsaPublicKey2), I get "Sun RSA public key, 3696 bits" and i don't know why.
Thanks!
On the recipient side, do you validate the X.509 certificate issuer, subject and chain before trusting the key? Signature validation must not be attempted before the recipient is certain that it can trust the certificate included in the JWS.
Another note: Do not include the public JWK in the JWS header. This should only be used for ephemeral public keys in ECDH (a different alg used for JWE). Passing the certificate chain in the JWS header is sufficient, but you must validate it / find out if the certificate can be trusted, before using its public key.
The library will not validate / find out if the certificate can be trusted for you!
If the second signature validation fails, then probably the key used to sign the JWS and the one that came with the X.509 certificate are not the same (as suggested by the different reported lengths - 2048 bits vs. 3696 bits).

Bare Metal Cloud - How to set authorized ssh keys for compute instances?

I have successfully provisioned Bare Metal Cloud compute instances using the following code:
public static Instance createInstance(
ComputeClient computeClient,
String compartmentId,
AvailabilityDomain availabilityDomain,
String instanceName,
Image image,
Shape shape,
Subnet subnet
) {
LaunchInstanceResponse response = computeClient.launchInstance(
LaunchInstanceRequest.builder()
.launchInstanceDetails(
LaunchInstanceDetails.builder()
.availabilityDomain(availabilityDomain.getName())
.compartmentId(compartmentId)
.displayName(instanceName)
.imageId(image.getId())
.shape(shape.getShape())
.subnetId(subnet.getId())
.build())
.build());
return response.getInstance();
}
However, I can't SSH into any instances I create via the code above, because there's no parameter on launchInstance to pass in the public key of my SSH keypair.
How can I tell the instance what SSH public key to allow? I know it must be possible somehow since the console UI allows me to provide the SSH public key as part of instance creation.
According to the launch instance API documentation, you need to pass your SSH public key via the ssh_authorized_keys field of the metadata parameter:
Providing Cloud-Init Metadata
You can use the following metadata key names to provide information to Cloud-Init:
"ssh_authorized_keys" - Provide one or more public SSH keys to be
included in the ~/.ssh/authorized_keys file for the default user on
the instance. Use a newline character to separate multiple keys. The
SSH keys must be in the format necessary for the authorized_keys file
The code for this in the Java SDK looks like this:
public static Instance createInstance(
ComputeClient computeClient,
String compartmentId,
AvailabilityDomain availabilityDomain,
String instanceName,
Image image,
Shape shape,
Subnet subnet
) {
String sshPublicKey = "ssh-rsa AAAAB3NzaC1y...key shortened for example...fdK/ABqxgH7sy3AWgBjfj some description";
Map<String, String> metadata = new HashMap<>();
metadata.put("ssh_authorized_keys", sshPublicKey);
LaunchInstanceResponse response = computeClient.launchInstance(
LaunchInstanceRequest.builder()
.launchInstanceDetails(
LaunchInstanceDetails.builder()
.availabilityDomain(availabilityDomain.getName())
.compartmentId(compartmentId)
.displayName(instanceName)
.imageId(image.getId())
.metadata(metadata)
.shape(shape.getShape())
.subnetId(subnet.getId())
.build())
.build());
return response.getInstance();
}
Then the instance will allow you to SSH to it using the SSH keypair for that public key.