How to Store/Retrieve Rsa Public/Private Key

How to store/retrieve RSA public/private key

What I have done successfully is to store the keys as XML. There are two methods in RSACryptoServiceProvider: ToXmlString and FromXmlString. The ToXmlString will return an XML string containing either just the public key data or both the public and private key data depending on how you set its parameter. The FromXmlString method will populate the RSACryptoServiceProvider with the appropriate key data when provided an XML string containing either just the public key data or both the public and private key data.

How to store and retrieve an RSA public key in Android keystore which is generated from server side application?

I'm not sure what parts are confusing you, or what exactly you are trying to achieve. KeyStore can only hold three types of entries: symmetric keys, private keys, and certificates. Therefore, if you want to store a public key it must be formatted into a certificate. Whether your application uses any of the other features of X509 certificates is up to you.

It's also not clear if you want to use any old keystore on Android, or the AndroidKeyStore. The latter offers enhanced features, but whether you need them or not is dependent on your threat model. In any event, here is an example that shows how to import a google public key into the Android Keystore, how to set some properties on it, and how to use it to encrypt an AES key.

import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.util.Base64;
import android.util.Log;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;

public class MainActivity extends AppCompatActivity {

private static final String THE_CERT = "-----BEGIN CERTIFICATE-----\n" +
"MIIIPjCCByagAwIBAgIIWcyJ5Cnzp3UwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE\n" +
"BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl\n" +
"cm5ldCBBdXRob3JpdHkgRzIwHhcNMTgwMzEzMTgzMDQ1WhcNMTgwNjA1MTgxNjAw\n" +
"WjBmMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN\n" +
"TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEVMBMGA1UEAwwMKi5n\n" +
"b29nbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtXqeeS6r\n" +
"sLfE5dx5asD7dngw0Dev9rhgDYM9kAuV9VxbZJ2ehZM4Nk1zGGSlqidgRWsVSNrx\n" +
"qb513IyrtxDSvTTGh8ihFGNTL/H61e+cYU565RCw4siOU0IevyhynPVh8D38pe5U\n" +
"bkGDmkiP7tOVozQE+3Q7l6xaIvlq9hIAb0aTWdJ6AOm3r/iMRdiUv/kxIienQ4v/\n" +
"RY/h3K/llz1E+S+TAyM2+As8o2nRMGrp9/hg8zIs3CLLv2km9VS/fgTQrM5pcfDf\n" +
"iX6Tgzb+6RSGHnT7GgNA3R1LXo96gnwf3zlX3SqpvV8pQf2Y3TxhLRB7J28yZFef\n" +
"P6d9t2EqlHZv+wIDAQABo4IFCzCCBQcwEwYDVR0lBAwwCgYIKwYBBQUHAwEwggPh\n" +
"BgNVHREEggPYMIID1IIMKi5nb29nbGUuY29tgg0qLmFuZHJvaWQuY29tghYqLmFw\n" +
"cGVuZ2luZS5nb29nbGUuY29tghIqLmNsb3VkLmdvb2dsZS5jb22CFCouZGI4MzM5\n" +
"NTMuZ29vZ2xlLmNuggYqLmcuY2+CDiouZ2NwLmd2dDIuY29tghYqLmdvb2dsZS1h\n" +
"bmFseXRpY3MuY29tggsqLmdvb2dsZS5jYYILKi5nb29nbGUuY2yCDiouZ29vZ2xl\n" +
"LmNvLmlugg4qLmdvb2dsZS5jby5qcIIOKi5nb29nbGUuY28udWuCDyouZ29vZ2xl\n" +
"LmNvbS5hcoIPKi5nb29nbGUuY29tLmF1gg8qLmdvb2dsZS5jb20uYnKCDyouZ29v\n" +
"Z2xlLmNvbS5jb4IPKi5nb29nbGUuY29tLm14gg8qLmdvb2dsZS5jb20udHKCDyou\n" +
"Z29vZ2xlLmNvbS52boILKi5nb29nbGUuZGWCCyouZ29vZ2xlLmVzggsqLmdvb2ds\n" +
"ZS5mcoILKi5nb29nbGUuaHWCCyouZ29vZ2xlLml0ggsqLmdvb2dsZS5ubIILKi5n\n" +
"b29nbGUucGyCCyouZ29vZ2xlLnB0ghIqLmdvb2dsZWFkYXBpcy5jb22CDyouZ29v\n" +
"Z2xlYXBpcy5jboIUKi5nb29nbGVjb21tZXJjZS5jb22CESouZ29vZ2xldmlkZW8u\n" +
"Y29tggwqLmdzdGF0aWMuY26CDSouZ3N0YXRpYy5jb22CCiouZ3Z0MS5jb22CCiou\n" +
"Z3Z0Mi5jb22CFCoubWV0cmljLmdzdGF0aWMuY29tggwqLnVyY2hpbi5jb22CECou\n" +
"dXJsLmdvb2dsZS5jb22CFioueW91dHViZS1ub2Nvb2tpZS5jb22CDSoueW91dHVi\n" +
"ZS5jb22CFioueW91dHViZWVkdWNhdGlvbi5jb22CByoueXQuYmWCCyoueXRpbWcu\n" +
"Y29tghphbmRyb2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5jb22CG2Rl\n" +
"dmVsb3Blci5hbmRyb2lkLmdvb2dsZS5jboIcZGV2ZWxvcGVycy5hbmRyb2lkLmdv\n" +
"b2dsZS5jboIEZy5jb4IGZ29vLmdsghRnb29nbGUtYW5hbHl0aWNzLmNvbYIKZ29v\n" +
"Z2xlLmNvbYISZ29vZ2xlY29tbWVyY2UuY29tghhzb3VyY2UuYW5kcm9pZC5nb29n\n" +
"bGUuY26CCnVyY2hpbi5jb22CCnd3dy5nb28uZ2yCCHlvdXR1LmJlggt5b3V0dWJl\n" +
"LmNvbYIUeW91dHViZWVkdWNhdGlvbi5jb22CBXl0LmJlMGgGCCsGAQUFBwEBBFww\n" +
"WjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcyLmNydDAr\n" +
"BggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2NzcDAdBgNV\n" +
"HQ4EFgQU2Xh9D7F5dJYCBqsWcKChI16NReswDAYDVR0TAQH/BAIwADAfBgNVHSME\n" +
"GDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAhBgNVHSAEGjAYMAwGCisGAQQB1nkC\n" +
"BQEwCAYGZ4EMAQICMDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9wa2kuZ29vZ2xl\n" +
"LmNvbS9HSUFHMi5jcmwwDQYJKoZIhvcNAQELBQADggEBAFxBsH2U6j4KzZbNcyN1\n" +
"UGiJnMn64DIXH8wsWrFEGAq3ONRhPgKd3AnbaBUdNdrRgOhfA3RtLvvnxsKn0rX6\n" +
"Oz8+p5DZxJooUgWlet9NounLDe5um6m5NqLIGefdI49Ukn6IwBtCO5DD7rZTygTa\n" +
"B499H9N0ixI9wGBdlZ37tOpCxayNb08eizU1uQEhb1/oxnXf0e6trPfC8krDL0Ks\n" +
"Pyf3JgB5oBTiNAfix2zme1FrpXcKehOj2urnLQRr5EpminCJ+0uHI1sqiJbcSHrU\n" +
"6TPQcOzZ7/haw1yY2bpy+sB4oXUMaNJxh6e2AiCeVf4MtX9EsYEnhsfc2XS50J32\n" +
"nKo=\n" +
"-----END CERTIFICATE-----";

private void doExample() {
try {
X509Certificate googleCert = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream(THE_CERT.getBytes(StandardCharsets.UTF_8)));
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
KeyProtection keyProtection = new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA256)
.setRandomizedEncryptionRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
.setUserAuthenticationRequired(false)
.build();
keyStore.load(null);
keyStore.setEntry("googlecert", new KeyStore.TrustedCertificateEntry(googleCert), keyProtection);
// Now use the entry
KeyGenerator aesKeygen = KeyGenerator.getInstance("AES");
aesKeygen.init(128);
Key aesKey = aesKeygen.generateKey();
// Wrap key for transport
KeyStore keyStore2 = KeyStore.getInstance("AndroidKeyStore");
keyStore2.load(null);
Certificate googleCert2 = keyStore2.getCertificate("googlecert");
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding");
rsaCipher.init(Cipher.WRAP_MODE, googleCert2);
byte[] rsaEncrypted = rsaCipher.wrap(aesKey);
Log.d("crypt", Base64.encodeToString(rsaEncrypted, Base64.DEFAULT));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

How to store RSA Private Key into app given by backend?

Probably you should change your server approach to public key exchange and generate key separately on android device. This way would be much secure.

You must store private keys with a certificate in KeyStore. Here are steps how you can achieve this:

Step 1. Decode the Base64 PKCS#8 to get an instance of PrivateKey:

PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(ks);

Step 2. The case might be that your server sends a certificate with private key or PKCS#8 blob also contains the public key.

Step 3. If server does not send certificate, you'll need to generate certificate for private key. Here is example using BouncyCastle.

Step 4. Store key on KeyStore:

X509Certificate certificate = ... // get certificate for private key or generate
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
keystore.setKeyEntry("MyAlias", privateKey, null, new Certificate[] { certificate });

If you really have to transmit private key to device from server, more secure case might be following:

  1. Generate AES key on device.
  2. Get server's public key first.
  3. Wrap generated AES key using that public key.
  4. Transmit encrypted AES key to server.
  5. Decrypt encrypted AES key on server side using private key.
  6. Encrypt private key using AES key, and transfer it to device.

The question was updated, so updated answer:

If you have to keep public private keypair in the app, I'd recommend keeping bytes of key using Android NDK, and strongly obfuscating it.

However, if I were you, as obfuscation tools are expensive for strong Android C++ code encryption, I'd keep those static key on server side, not hardcoded inside app. Then I'd send static key to device using the steps I mentioned before using symmetric encryption.

But if you choose using NDK option, it's better than storing key on file or on Java code also, but not fully bulletproof. Once user opens the app, you can store the key retrieved from C++ code in KeyStore, so, you make sure it's safe.

So, if you want to go with fastest option for keeping private key secure inside app binary, go for NDK option, and in future you can obfuscate it. If you have time to do some server side arrangements for transmitting private key, then storing on keystore, then go for steps I wrote.

Here are few resources might help you for NDK:

https://androidsecurity.info/2016/12/15/storing-your-secure-information-in-the-ndk/

https://medium.com/@abhi007tyagi/storing-api-keys-using-android-ndk-6abb0adcadad/

How to store private and public key into pem file generated by rsa module of python

The Github site of Python RSA refers via its homepage to this documentation, according to which the library has dedicated methods to export the keys in PKCS#1 format (methods rsa. PublicKey#save_pkcs1() or rsa.PrivateKey#save_pkcs1()) or to import them (classmethods rsa.PublicKey.load_pkcs1() or rsa.PrivateKey.load_pkcs1()). As encodings PEM (text) or DER (binary) is supported, e.g.:

import rsa

# Use at least 2048 bit keys nowadays, see e.g. https://www.keylength.com/en/4/
publicKey, privateKey = rsa.newkeys(2048)

# Export public key in PKCS#1 format, PEM encoded
publicKeyPkcs1PEM = publicKey.save_pkcs1().decode('utf8')
print(publicKeyPkcs1PEM)
# Export private key in PKCS#1 format, PEM encoded
privateKeyPkcs1PEM = privateKey.save_pkcs1().decode('utf8')
print(privateKeyPkcs1PEM)

# Save and load the PEM encoded keys as you like

# Import public key in PKCS#1 format, PEM encoded
publicKeyReloaded = rsa.PublicKey.load_pkcs1(publicKeyPkcs1PEM.encode('utf8'))
# Import private key in PKCS#1 format, PEM encoded
privateKeyReloaded = rsa.PrivateKey.load_pkcs1(privateKeyPkcs1PEM.encode('utf8'))

plaintext = "vinay kumar shukla".encode('utf8')
print("Plaintext: ", plaintext)

ciphertext = rsa.encrypt(plaintext, publicKeyReloaded)
print("Ciphertext: ", ciphertext)

decryptedMessage = rsa.decrypt(ciphertext, privateKeyReloaded)
print("Decrypted message: ", decryptedMessage)

Get RSA public key from private key modulus and private exponent

Generally the RSA private key contains the following data:

  • n - semiprime modulus

  • d - private exponent

  • p & q - prime factors of n

  • e - public exponent

At a minimum, the private key must contain:

  • n and d.

So to answer your questions:

can I get the associated public key modulus?

Yep, you already have it. It's the same n used by the private key.

can I get the public exponent?

Not easily without knowing p and q, though you can guess at it, it's nearly always a small prime, most commonly either 3 or 65537.

Try both and check if ciphertext is valid.

How to save RSA publicKey/privateKey NOT in Keychain

Since you have to store only public and private key and not the whole certificate, can not use the internal keychain and the keys are generated on the device it would be sufficient if you save your public and private key in the NSUserDefaults:

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
//saving the data
[prefs setObject"<your public key data>" forKey:@"PublicKey"];
[prefs setObject"<your private key data>" forKey:@"PrivateKey"];

//reading the data
NSString *publicKey = [prefs stringForKey:@"PublicKey"];
NSString *privateKey = [prefs stringForKey:@"PrivateKey"];

This store is rather insecure, so I would suggest that you encrypt your data like this: iOS 5: Data encryption AES-256 EncryptWithKey: not found. Be aware, that symmetric encryption is not secure if you store the key in your application! You should use some user input to generate the key.

Hope this helps.

How to store RSA private keys in the client's browser for better UX?

After a couple of thoughts I decided to encrypt the RSA private key with the user master password. Since the master password is nowhere stored, I assume that it is safe to store the encrypted private key into the user's local browser storage. This solution makes it possible to automatically provide the encrypted private key on each password request, but forces the user to enter his password on each request, which is fine for me for now.

If anybody has a better solution, I would be glad if you can post your solution here.



Related Topics



Leave a reply



Submit