So I have a PublicKey in Java, and I need to send a post request to the server with the key in it, then read the key server side, and send some data encrypted with it!
I succeeded at:
Generating the keypair (duh)
Encrypting and decrypting data with it in the Java program
Maybe: making a pem formatted key from it, I'm not sure
String phpPublic = ("-----BEGIN PUBLIC KEY-----"+Base64.encodeToString(MainActivity.instance.rsa.readPublicKeyFromFile(MainActivity.instance.rsa.PUBLIC_CLIENT_KEY_FILE).getEncoded(),Base64.DEFAULT)+"-----END PUBLIC KEY-----");
I think this does it, but I'm not sure! And would it be the same process to convert private keys to pem, just to make PUBLIC -> PRIVATE in the header and footer.
I don't know if converting to pem is really necessary, if it's not, please suggest a better way to do it.
This is how I do it in PHP, but I'm 99% sure it is wrong
$PubKey = openssl_pkey_get_public($publicPem);
$encrypted;
openssl_public_encrypt($toEncode, $encrypted, $PubKey);
echo $encrypted;
can you post a sample key?
in lieu of that i do think you'd have better success with phpseclib a pure php rsa implementation. it supports a lot more key formats than openssl does and it'll auto detect the type too.
example:
<?php
include('Crypt/RSA.php');
$rsa = new Crypt_RSA();
$rsa->loadKey('...');
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
echo $rsa->encrypt('whatever');
Related
I am trying to SSH to EC2 using JSch Library from Java code. I referred this link in SO How can I use .pem files content as a string in ec2 connection using JSch library and tried couple of things as mentioned below but in vain. Can someone please guide me on how to achieve my objective?
Objective
I have a PEM file like this. I dont want to store my PEM file anywhere in AWS, hence my approach is to extract an equivalent string that I can encode and store in database and decode it from java for passing the parameter to addIdentity method that takes these parameters:
addIdentity(String name, byte[] prvkey, byte[] pubkey, byte[] passphrase)
throws JSchException
-----BEGIN RSA PRIVATE KEY-----
MIIepsdfAIBAAKCAQEAtBk068z
...
xVNdhlDy6asdk9wsdQ==
-----END RSA PRIVATE KEY-----
For my objective, my addIdentity method would be like this I believe:
addIdentity ("username","{privatekey string converted to byte array}",null, null)
I am trying to understand how that string can be formed? I am very new to cryptography, but during this process I learnt that since my PEM has BEGIN RSA PRIVATE KEY, it's PKCS1 format. Does JSch support PKCS1 format or it needs to be converted to PKSC8?
Secondly, I learnt that the body is encoded with Base64, so I even tried decoding the string with Base64 after stripping off all the carriage returns, header and footer, which gave me error like this
Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
Below are some of the additional links I tried following up but have not been able to resolve.
JSch getting "invalid privatekey:" while trying to load an RSA private key by KeyPairGenerator
Java - How to decode a Base64 encoded Certificate
Converting a PEM private key file to a JAVA PrivateKey Object
Hope someone can guide me in the right direction.
Thanks!
I figured out the answer.
Below post gave me a direction.
JSch: addIdentity from private key stored on hdfs
To anyone else who is looking to solve a similar requirement, ensure that you are not stripping off the header, footer information. This took most of my time to debug as most of the blogs/SO posts directed towards stripping those characters. In Java, your string must have the carriage returns else you might get a very different byte array.
String x = "-----BEGIN RSA PRIVATE KEY-----\r\n" +
"MIIEpAIBAAKCAQEAtBk\Q/z4QAgk+LN3IUajqjUv7IucsCd4SebbQvah5t4WJ\r\n"
Convert the string to byte array using "US-ASCII" charset. Use following JSch method if you don't have a passphrase:
jsch.addIdentity("username",{bytearray of x},null, null)
Note: ensure that you are passing an unsigned byte array like:
Array (45, 45, 69,...)
and NOT
Array (45, -35, -125,...)
I have a token in String format such as:
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.K52jFwAQJH-DxMhtaq7sg5tMuot_mT5dm1DR_01wj6ZUQQhJFO02vPI44W5nDjC5C_v4pW1UiJa3cwb5y2Rd9kSvb0ZxAqGX9c4Z4zouRU57729ML3V05UArUhck9ZvssfkDW1VclingL8LfagRUs2z95UkwhiZyaKpmrgqpKX8azQFGNLBvEjXnxxoDFZIYwHOno290HOpig3aUsDxhsioweiXbeLXxLeRsivaLwUWRUZfHRC_HGAo8KSF4gQZmeJtRgai5mz6qgbVkg7jPQyZFtM5_ul0UKHE2y0AtWm8IzDE_rbAV14OCRZJ6n38X5urVFFE5sdphdGsNlA.gjI_RIFWZXJwaO9R.oaE5a-z0N1MW9FBkhKeKeFa5e7hxVXOuANZsNmBYYT8G_xlXkMD0nz4fIaGtuWd3t9Xp-kufvvfD-xOnAs2SBX_Y1kYGPto4mibBjIrXQEjDsKyKwndxzrutN9csmFwqWhx1sLHMpJkgsnfLTi9yWBPKH5Krx23IhoDGoSfqOquuhxn0y0WkuqH1R3z-fluUs6sxx9qx6NFVS1NRQ-LVn9sWT5yx8m9AQ_ng8MBWz2BfBTV0tjliV74ogNDikNXTAkD9rsWFV0IX4IpA.sOLijuVySaKI-FYUaBywpg
Now I want to decrypt this String through some java library and ultimately want to access the payload. Anyone done this so far ?
The assertion you shared with us is a JWE serialized in its compact representation. It has 5 parts separated by a dot (.) which are:
Part 1: the header (eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ)
Part 2: the encrypted key - depending on the algorithm, it may be an empty string - (K52jFwAQJH-DxMhtaq7sg5tMuot_mT5dm1DR_01wj6ZUQQhJFO02vPI44W5nDjC5C_v4pW1UiJa3cwb5y2Rd9kSvb0ZxAqGX9c4Z4zouRU57729ML3V05UArUhck9ZvssfkDW1VclingL8LfagRUs2z95UkwhiZyaKpmrgqpKX8azQFGNLBvEjXnxxoDFZIYwHOno290HOpig3aUsDxhsioweiXbeLXxLeRsivaLwUWRUZfHRC_HGAo8KSF4gQZmeJtRgai5mz6qgbVkg7jPQyZFtM5_ul0UKHE2y0AtWm8IzDE_rbAV14OCRZJ6n38X5urVFFE5sdphdGsNlA)
Part 3: the initialisation vector - IV depending on the algorithm, it may be an empty string - (gjI_RIFWZXJwaO9R)
Part 4: the cyphertext (oaE5a-z0N1MW9FBkhKeKeFa5e7hxVXOuANZsNmBYYT8G_xlXkMD0nz4fIaGtuWd3t9Xp-kufvvfD-xOnAs2SBX_Y1kYGPto4mibBjIrXQEjDsKyKwndxzrutN9csmFwqWhx1sLHMpJkgsnfLTi9yWBPKH5Krx23IhoDGoSfqOquuhxn0y0WkuqH1R3z-fluUs6sxx9qx6NFVS1NRQ-LVn9sWT5yx8m9AQ_ng8MBWz2BfBTV0tjliV74ogNDikNXTAkD9rsWFV0IX4IpA)
Part 5: the Additional Authentication Data - AAD - (sOLijuVySaKI-FYUaBywpg)
The header indicates at least the
Key Encryption Algorithm (alg) used to encrypt the content encryption key (CEK)
Content Encryption Algorithm (enc) used in conjunction with the CEK to encrypt the content.
In your case, The alg is RSA-OAEP and the enc is A128GCM.
According to these algorithm, you should have a RSA private key to decrypt the CEK and then use it to decrypt the cyphertext.
https://jwt.io mentioned in the accepted answer will not be useful as it does not support JWE, but JWS. The result shown with a JWE input will not give you the decrypted payload.
However, the https://connect2id.com/products/nimbus-jose-jwt resource will help you as it seems that the algorithms used for your token are supported.
You probably don't necessarily need a library:
String token = eyJ....;
String[] splitToken = JWTEncoded.split("\\.");
// splitToken[0] is the header, splitToken[1] is the payload and
// splitToken[2] is the signature
byte[] decodedBytes = Base64.decode(splitToken[1], Base64.URL_SAFE);
// You don't have to convert it to string but it really depends on what type
// data you expect
String payload = new String(decodedBytes, "UTF-8");
https://jwt.io has a nice little decrypter for you to test data
In regards to JWE the only library I could find is this and an example to unencrypted JWE tokens can be found at the bottom of this page.
Note: I haven't tested this library so I won't be of much use beyond this, but it seems fairly straight forward.
Assume I have the following Java code to generate a Public-private keypair:
KeyPairGenerator generator = KeyPairGenerator.getInstance ("RSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
generator.initialize (1024, random);
KeyPair pair = generator.generateKeyPair();
RSAPrivateKey priv = (RSAPrivateKey)pair.getPrivate();
RSAPublicKey pub = (RSAPublicKey)pair.getPublic();
// Sign a message
Signature dsa = Signature.getInstance("SHA1withRSA");
dsa.initSign (priv);
dsa.update ("Hello, World".getBytes(), 0, "Hello, World".length());
byte[] out = dsa.sign();
/* save the signature in a file */
FileOutputStream sigfos = new FileOutputStream("sig");
sigfos.write(out);
sigfos.close();
How would one go about and decrypt the file "sig" in PHP? I've read the post: https://stackoverflow.com/a/1662887/414414 which supplies a function to convert a DER file to PEM (Assume I also save the public key from Java).
I have tried something like:
$key = openssl_pkey_get_public ("file://pub_key.pem");
$data = null;
openssl_public_decrypt ( file_get_contents ("sig"), $data, $key);
echo $data, "\n";
It successfully decrypts the message, but it is many weird characters.
Our scenario is a Java client that is sending messages to a PHP server, but encrypts the data with a private key. PHP knows about the public key, which it should use to decrypt and validate the message.
I've read a lot of posts regarding this issue here on SO, but I've come to realize that this is a bit specific issue, especially if there's different algorithms in use, etc. So sorry if this may be a duplicate.
Any feedbacks are greatly appreciated!
an "RSA signature" is usually more than just "encrypt with private key, decrypt with public key", since Public key protocols like PKCS#1 also specify padding schemes, and all signature schemes will encrypt a digest of the message, instead of the full message. I cannot find any documentation if java's signature scheme uses the signature padding scheme specified in PKCS#1, but my suspicion is that it is.
If it is, you will instead want to use the openssl_verify method in PHP, documented here. This will return a 0 or 1 if the signature is invalid or valid, respectively.
In the event that Java does not use a padding scheme, your issue is that the data encrypted in the signature is a hash of the message, instead of the message itself (you can see in the Java code that it uses the SHA-1 hash algorithm). So on the PHP side, you will need to take the sha1 hash of your message using the sha1 method with $raw_output set to true, and compare those strings to ensure your message is valid.
From the snippet
$key = openssl_pkey_get_public ("file://pub_key.pem");
It looks like you're referencing the public key, which would be the wrong one to decrypt. Double check ?
I've implemented a security system in my app with RSA.
I've generated the public and private keys using Keyczar Tool. Using just keyczar I can encrypt with public key and decrypt with private key with no problems at all.
I want to encrypt some data in JS and then pass it to Java. For this I'm trying to use this library (https://github.com/ziyan/javascript-rsa) but I'm not being able to encrypt the data or at least not encrypting the data correctly (it's bigger than with keyczar).
How can I encrypt with this tool using my public key? Can anyone help me?
There is not a javascript client for keyczar, so if you want to produce ciphertext consumable by keyczar.
Look at the keyczar public key format you will need to provide the public key info from your server to your javascript encryptor.
http://code.google.com/p/keyczar/wiki/RsaPublicKey
Alternatively, it looks like your javascript library will read PEM format. You can use the KeyczarTool to export your public key in PEM format with the export.
Look at the Keyczar ciphertext format for rsa
http://code.google.com/p/keyczar/wiki/CiphertextFormat
You'll need to prepend the header to your ciphertext generate with the javascript.
Technically you need to produce a keyhash to append a proper header, but a given header will always be identical for a given key regardless of the ciphertext, so you could just provide it with your public key generated by the java keyczar code.
I am trying to implement a PKI verification scheme, where a message string is signed with a private key on server, the signature is stored on the client along with the message string. The client then verifies the signature using a public key.
The restrictions of my environment are, the server is Google App Engine and the client is a Java program. I have played with Java-only and Python-only solutions of PKI verification and got them to work, however when doing one operation in Python and another in Java is posing problem, mainly due to Key file format restrictions and my limited understanding of cryptography terminology.
One of the biggest limitations is crypto support in GAE. The only library supported is PyCrypto and this library can't read public/private keys stored in PEM, DER or X509 formats. As far as I could find, only M2Crypto supports reading from these files, but it can't be used inside GAE because it's a wrapper around openssl, so not a pure python solution. Even if I could find a way to translate the public/private keys from PEM/DER/X509 to the format that PyCrypto understands, that will work for me. But I couldn't find any way to do it. Any ideas there?
I found one possible solution in the form of tlslite. tlslite could read a private key from PEM file and create a signature. Here is the code.
from tlslite.utils.cryptomath import bytesToBase64
from tlslite.utils.keyfactory import parsePEMKey
s = open('private.pem').read()
key = parsePEMKey(s)
doc = 'Sample text'
bytes = array('B')
bytes.fromstring(doc)
print bytesToBase64(key.sign(bytes))
The corresponding Java code I used to verify the signature is.
String signAlgo = "SHA1WithRSAEncryption";
// read public key from public.der
byte[] encodedKey = new byte[294]; // shortcut hardcoding
getAssets().open("public.der").read(encodedKey);
// create public key object
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pk = kf.generatePublic(publicKeySpec);
// read signature (created by python code above)
byte[] encodedSig = new byte[345];
getAssets().open("signature.txt").read(encodedSig);
byte[] decodedSig = Base64.decodeBase64(encodedSig);
// Do verification
Signature verifyalg = Signature.getInstance(signAlgo);
verifyalg.initVerify(pk);
verifyalg.update(message.getBytes());
Log.d(TAG, "Verif : "+verifyalg.verify(decodedSig));
The verification fails.
I suspected if the tlslite is using different algorithm for signature creation than what the java code expects.
So I tried to find that out.
On python side
print key.getSigningAlgorithm()
gave me
pkcs1-sha1
on Java side, I tried to find all supported algorithms with this code:
Set<String> algos = java.security.Security.getAlgorithms("Signature");
for(String algo : algos) {
Log.d(TAG, algo);
}
That gave me
MD4WithRSAEncryption
RSASSA-PSS
SHA1withDSA
SHA1withRSA/ISO9796-2
1.2.840.113549.1.1.10
SHA512withRSA/PSS
MD5withRSA/ISO9796-2
DSA
SHA512WithRSAEncryption
SHA224withRSA/PSS
NONEWITHDSA
SHA256withRSA/PSS
SHA224WithRSAEncryption
SHA256WithRSAEncryption
SHA1withRSA/PSS
SHA1WithRSAEncryption
SHA384withRSA/PSS
SHA384WithRSAEncryption
MD5WithRSAEncryption
I tried all the SHA1 values on the Java side. But none helped to verify the signature generated by tlslite with pkcs1-sha1 algo. Any idea about this mapping?
These are different operations. In Python, you need to use hashAndSign. The default happens to be SHA1 hash.
Keyczar should work fine on App Engine, and is available in both Java and Python flavours.