The user has saved a .p12-file (e.g. his S/MIME certificate) on SD-Card. I want to load this certificate (or the extracted private and public key) into the AndroidKeyStore.
File file = new File(pathToP12File);
Certificate c = null; // TODO: convert file into something I can load into the keystore
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
ks.setCertificateEntry("myCertAlias", c);
What's the best way to convert the file into something which can be set as a certificate entry in the keystore?
It's possible to interpret the p12-file as a keystore, extract the certificate and load it into the AndroidKeyStore.
private void getCertsFromP12(String pathToFile, String passphrase){
try {
KeyStore p12 = KeyStore.getInstance("pkcs12");
p12.load(new FileInputStream(pathToFile), passphrase.toCharArray());
Enumeration e = p12.aliases();
while (e.hasMoreElements()) {
String alias = (String) e.nextElement();
X509Certificate c = (X509Certificate) p12.getCertificate(alias);
addCertificateToKeyStore(c);
}
} catch (Exception e) {}
}
private void addCertificateToKeyStore(X509Certificate c) {
try {
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
ks.setCertificateEntry("myCertAlias", c);
} catch (Exception e){}
}
If you want to install your certificate into the android KeyChain you can use your P12 to install it directly like in the next method:
InputStream is = new ByteArrayInputStream(pkcs12);
BufferedInputStream bis = new BufferedInputStream(is);
byte[] keychainP12 = new byte[bis.available()];
bis.read(keychainP12);
Intent installIntent = KeyChain.createInstallIntent();
installIntent.putExtra(KeyChain.EXTRA_PKCS12, keychainP12);
context.startActivity(installIntent);
Related
I want to sign the pdf using pdf digest. I have created the hash using below code,
byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
md = MessageDigest.getInstance("SHA256","BC");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();
At the end I need to attach this signature to my pdf. I have found one solution Create pkcs7 signature from file digest, but the algorithm used in the link is SHA256withRSA. My privatekey is genearted using EC algorithm and I need to use SHA256withECDSA.Is it possible to just sign the Hash using SHA256withECDSA and attach the signature to the pdf using PDFBox ExternalSigning Interface.
There are several situations in which Adobe calls a signer's certificate invalid even though apparently it is valid; in the case at hand in particular:
Key usage or Extended key usage values not appropriate
PAdES signature misses an ESS signing-certificate-v2 attribute
Key usage or Extended key usage values not appropriate
This is based on the information the OP first published as an answer
I tried below code still the pdf says Signature is invalid. Can you please check the code,
[...]
I have attached the pdf . Pdf file created
Indeed, Adobe Reader says the signature is invalid, but look more closely:
It says "Document has not been modified since this signature was applied" - This means that the signature is mathematically correct!
The issue is that the "Signer's certificate is invalid", and the reason for this can be seen when digging into the signature property dialogues:
Thus, the problem is that your signer certificate is Not valid for usage.
This is due to the highlighted attribute, while the Key Usage Digital Signature is ok, the "Extended key usage" 1.3.6.1.5.5.8.2.2 (OID for IPSEC Protection) is not!
According to the Adobe Digital Signatures Guide for IT, Adobe Acrobat accepts only
one or more of the following Key usage values (if any)
nonRepudiation
signTransaction (11.0.09 only)
digitalSignature (11.0.10 and later)
and one or more of the following Extended key usage values (if any)
emailProtection
codeSigning
anyExtendedKeyUsage
1.2.840.113583.1.1.5 (Adobe Authentic Documents Trust)
Due to its IPSEC Protection extended key usage value, therefore, your certificate is not considered valid for signing PDF documents.
This probably only is an issue in legacy ISO 32000-1 signatures, probably not in PAdES signatures.
PAdES signature misses an ESS signing-certificate-v2 attribute
This is based on the information the OP first published as an answer
I have created 2 pdf files, PDFA is signed using the digest of the pdf content with below code,
[...]
PDFA
PDFB is created with the same private key and certificate, but instead of digest I am using pdf document content directly which gives me valid signed pdf, PDFB code below,
[...]
PDFB
I think something is missing in the signing part of PDFA which I couldn't figure out.
Here the main difference is not whether you explicitly calculate the hash yourself or allow it to be calculated implicitly, the main difference is that the signature in PDFB includes an ESS signing-certificate-v2 attribute while the one in PDFA does not. This attribute is generated between
//PAdES - PDF Advanced Electronic Signature
and
//PAdES-end
As the comments already hint, this is only necessary for PAdES signatures, not for legacy ISO 32000-1 ones. The answer the OP took his original code from referred to creating a legacy ISO 32000-1 signature (and, therefore, works alright) while the OP creates a PAdES signature.
The presence of an ESS signing certificate attribute is required by the PAdES specification ETSI EN 319 142-1:
e) Generators shall use either the signing certificate or the signing-certificate v2 attribute, depending on the hash function, in accordance with ETSI EN 319 122-1.
(ETSI EN 319 142-1, section 6.3 PAdES baseline signatures)
It references the CAdES specification ETSI EN 319 122-1 which in turn requires
h) Requirement for SPO: ESS signing-certificate. The ESS signing-certificate attribute shall be used if the SHA-1 hash algorithm is used.
i) Requirement for SPO: ESS signing-certificate-v2. The ESS signing-certificate-v2 attribute shall be used when another hash algorithms than SHA-1 is used.
(ETSI EN 319 122-1, section 6.3 Requirements on components and services)
I tried below code still the pdf says Signature is invalid. Can you please check the code,
System.out.println("Hash Signing started");
List<Certificate> certList = getFormatCertificate(strCertificate);
PrivateKey privateKey;
CMSSignedData s = null;
Security.addProvider(new BouncyCastleProvider());
byte[] signature = null;
try {
privateKey = loadPrivateKey(strPrivatekey);
byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
md = MessageDigest.getInstance("SHA256","BC");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();
// Separate signature container creation step
JcaCertStore certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
Attribute attr = new Attribute(CMSAttributes.messageDigest,
new DERSet(new DEROctetString(digest)));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
//AlgorithmIdentifier sha256withECDSA = new DefaultSignatureAlgorithmIdentifierFinder().find(signerAlgorithm);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certList.get(certList.size()-1).getEncoded());
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
gen.addSignerInfoGenerator(builder.build(
new JcaContentSignerBuilder(signerAlgorithm).build(privateKey),
new JcaX509CertificateHolder(cert)));
//DErse
// gen.addSignerInfoGenerator(builder.build(
// new JcaContentSignerBuilder(sha256withRSA,
// new DefaultDigestAlgorithmIdentifierFinder().find(sha256withRSA))
// .build(PrivateKeyFactory.createKey(privateKey.getEncoded())),
// new JcaX509CertificateHolder(cert)));
gen.addCertificates(certs);
s = gen.generate(new CMSAbsentContent(), false);
System.out.println("Hash sign completed");
signature = s.getEncoded();// ConstructEcdsaSigValue(s.getEncoded());
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("GeneralSecurityException ::"+e.toString());
} catch (OperatorCreationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("OperatorCreationException ::"+e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("IOException ::"+e.toString());
} catch (CMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("CMSException ::"+e.toString());
}finally{
return signature;
}
I have attached the pdf . Pdf file created
#Mkl/Tilman : I have created 2 pdf files, PDFA is signed using the digest of the pdf content with below code,
System.out.println("Hash Signing started");
List<Certificate> certList = getFormatCertificate(strCertificate);
PrivateKey privateKey;
CMSSignedData s = null;
Security.addProvider(new BouncyCastleProvider());
byte[] signature = null;
try {
privateKey = loadPrivateKey(strPrivatekey);
/*byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
//md = MessageDigest.getInstance("SHA256","BC");
md = MessageDigest.getInstance("SHA-256");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();*/
MessageDigest md = MessageDigest.getInstance("SHA256", "BC");
byte[] digest = md.digest(IOUtils.toByteArray(content));
// Separate signature container creation step
JcaCertStore certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
Attribute attr = new Attribute(CMSAttributes.messageDigest,
new DERSet(new DEROctetString(digest)));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
//AlgorithmIdentifier sha256withECDSA = new DefaultSignatureAlgorithmIdentifierFinder().find(signerAlgorithm);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certList.get(certList.size()-1).getEncoded());
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
gen.addSignerInfoGenerator(builder.build(
new JcaContentSignerBuilder(signerAlgorithm).build(privateKey),
new JcaX509CertificateHolder(cert)));
//DErse
// gen.addSignerInfoGenerator(builder.build(
// new JcaContentSignerBuilder(sha256withRSA,
// new DefaultDigestAlgorithmIdentifierFinder().find(sha256withRSA))
// .build(PrivateKeyFactory.createKey(privateKey.getEncoded())),
// new JcaX509CertificateHolder(cert)));
gen.addCertificates(certs);
s = gen.generate(new CMSAbsentContent(), false);
System.out.println("Hash sign completed");
signature = s.getEncoded();// ConstructEcdsaSigValue(s.getEncoded());
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("GeneralSecurityException ::"+e.toString());
} catch (OperatorCreationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("OperatorCreationException ::"+e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("IOException ::"+e.toString());
} catch (CMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("CMSException ::"+e.toString());
}finally{
return signature;
}
PDFA
PDFB is created with the same private key and certificate, but instead of digest I am using pdf document content directly which gives me valid signed pdf, PDFB code below,
SignatureInterface signatureInterface = new SignatureInterface() {
#SuppressWarnings("rawtypes")
#Override
public byte[] sign(InputStream content) throws IOException {
try {
byte[] certificateByte = null;
Store certs = new JcaCertStore(certificates);
//PAdES - PDF Advanced Electronic Signature
//ESS - Enhanced Security Services
//ASN1 - Abstract Syntax Notation One-standard interface description language for defining data structures that can be serialized and deserialized in a cross-platform way
// Generating certificate hash
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(certificates.get(certificates.size()-1).getEncoded());
byte[] certHash = md.digest();
// Generating certificate hash ends
System.out.println("Cert hash generated");
//ESSCertIDv2 identifies the certificate from the hash
ESSCertIDv2 essCert1 =
new ESSCertIDv2(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256), certHash);
ESSCertIDv2[] essCert1Arr =
{
essCert1
};
SigningCertificateV2 scv2 = new SigningCertificateV2(essCert1Arr);
Attribute certHAttribute =
new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(scv2));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(certHAttribute);
AttributeTable at = new AttributeTable(v);
//Create a standard attribute table from the passed in parameters - certhash
CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(at){
protected Hashtable createStandardAttributeTable(Map parameters)
{
Hashtable result = super.createStandardAttributeTable(parameters);
result.remove(CMSAttributes.signingTime);
return result;
}
};
//PAdES-end
System.out.println("CMSAttributeTableGenerator generated");
SignerInfoGeneratorBuilder genBuild =
new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider());
genBuild.setSignedAttributeGenerator(attrGen);
//Get single certificate
org.spongycastle.asn1.x509.Certificate certas1 = org.spongycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificates.get(certificates.size()-1).getEncoded()));
// ContentSigner interface creates SHA256withECDSA signer using PvtKey
ContentSigner sha1Signer = new JcaContentSignerBuilder(signerAlgorithm).build(privateKey);
//Creates SignerInfoGenerator using X.509 cert and ContentSigner
SignerInfoGenerator sifGen = genBuild.build(sha1Signer, new X509CertificateHolder(certas1));
// CMSSignedDataGenerator generates a pkcs7-signature message
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addCertificates(certs);
gen.addSignerInfoGenerator(sifGen);
//Creates CMS message from PDF
CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
//Generate a CMS Signed Data object which can be carrying a detached CMS signature
//msg - content to be signed
CMSSignedData signedData = gen.generate(msg, false);
System.out.println("CMSSignedData is done");
return signedData.getEncoded();
} catch (GeneralSecurityException e) {
throw new IOException(e);
} catch (CMSException e) {
throw new IOException(e);
} catch (OperatorCreationException e) {
throw new IOException(e);
}
}
};
System.out.println("CMSSignedData is done2");
PDDocument pdDocument = PDDocument.load(inputfile);
System.out.println("pdDocument loaded");
pdDocument.addSignature(signature, signatureInterface);
PDFB
I think something is missing in the signing part of PDFA which I couldn't figure out.
I have a code in android to:
Generate ECDSA key-pair (Public Key and Private Key)
Generate Certificate Signing Request (CSR) from public key
Store Private Key
Then I send CSR to CA server. The CA server generate X.509 certificate.
Now I want to encrypt a string with public key from that X.509 certificate above. And then I will write android code to decrypt encrypted string using stored Private Key.
I have code to encrypt/ decrypt ECIES in android:
Here is my code:
///Gen Key
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("prime256v1");
try {
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA","SC");
g.initialize(spec, new SecureRandom());
KeyPair keyPair = g.generateKeyPair();
privateKey = keyPair.getPrivate();
publicKey = keyPair.getPublic();
Toast.makeText(MainActivity.this, "GEN KEY SUCCESS!!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
/////Encrypt
String origin = txtOrigin.getText().toString();
try {
Cipher c = Cipher.getInstance("ECIES","SC");
c.init(Cipher.ENCRYPT_MODE,publicKey);
encodeBytes = c.doFinal(origin.getBytes());
txtEncrypt.setText(Base64.encodeToString(encodeBytes,Base64.DEFAULT));
Toast.makeText(MainActivity.this, "ENCRYPT SUCCESS!!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
////Decrypt
byte[] decodeBytes = null;
try
{
Cipher c = Cipher.getInstance("ECIES","SC");
c.init(Cipher.DECRYPT_MODE,privateKey);
decodeBytes = c.doFinal(encodeBytes);
String deCrypt = new String(decodeBytes,"UTF-8");
txtDecrypt.setText(deCrypt);
Toast.makeText(MainActivity.this, "DECRYPT SUCCESS!!", Toast.LENGTH_SHORT).show();
}
catch (Exception ex)
{
ex.printStackTrace();
}
But I want to encrypt string using python with public key from X.509 certificate on my CA server and decrypt using my code above in android.
I have one .pfx a and .cer certificate. The first one is for signing data and the second one is for opening SSL.
How should I store certificates in android?
should I put them in Keystore in res/raw or in assets?
should I store them as single files in res/assets?
What is most efficient way to store them in order to manage future changes?
My current way of doing so:
// Create Keystore containing servers certificate
KeyStore keyStore = KeyStore.getInstance("BKS");
// Different versions of Android use different BKSs
// Need to export both versions using Portacle (1.9 worked for me)
int bks_version;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
bks_version = R.raw.keystore; //The BKS file
} else {
bks_version = R.raw.keystorev1; //The BKS (v-1) file
}
keyStore.load(activity.getResources().openRawResource(bks_version), "password");
I wrote a class which manages my certificates such as CAs for SSL and PFX or P12 for personal signatures.
I used internal storage and built in KeyStore.
If you are wondering where I got and alias for PFX, you have to know it, I haven't figure out a better way how to handle this problem in Android yet.
public class CertificateManager {
private static final String CUSTOMER_CERTIFICATE_STORE = "CustomerKeyStore.keystore";
private static final String CUSTOMER_CERTIFICATE_ALIAS = "CZ1212121218";
private static final String CUSTOMER_KS_PASSWORD = "eet";
private static final String SERVER_CERTIFICATE_STORE = "ServerKeyStore.keystore";
private static final String SERVER_CERTIFICATE_ALIAS = "ca";
private static final String SERVER_KS_PASSWORD = "eet";
/**
* Get Customer's Keystore, containing personal certificate.
* #param context
* #return Customer's Keystore
*/
private static KeyStore getCustomerKeystore(Context context){
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// Load Keystore form internal storage
FileInputStream fis = context.openFileInput(CUSTOMER_CERTIFICATE_STORE);
keyStore.load(fis, CUSTOMER_KS_PASSWORD.toCharArray());
return keyStore;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Keystore not found.");
}
}
/**
* Get customer's certificate for signature.
* #param context
* #return Customer's certificate
*/
public static X509Certificate getCustomersCertificate(Context context){
try {
KeyStore keyStore= getCustomerKeystore(context);
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(
CUSTOMER_CERTIFICATE_ALIAS,
new KeyStore.PasswordProtection(CUSTOMER_KS_PASSWORD.toCharArray())
);
return (X509Certificate) keyEntry.getCertificate();
} catch (Exception e) {
// Keystore not found ask user for uploading his certificate.
e.printStackTrace();
throw new RuntimeException("Wrong KeyStore");
}
}
/**
* Get customer's PrivateKey for encryption.
* #param context
* #return customer's PrivateKey
*/
public static PrivateKey getCustomersPrivateKey(Context context){
try {
KeyStore keyStore= getCustomerKeystore(context);
//return customer's certificate
return (PrivateKey)keyStore.getKey(CUSTOMER_CERTIFICATE_ALIAS, CUSTOMER_KS_PASSWORD.toCharArray());
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Wrong KeyStore");
}
}
/**
* Loads Customer .p12 or .pfx certificate to keystore with password to Internal Storage
* #param context
* #return customer's PrivateKey
*/
public static void loadCustomerCertificate(Context context, InputStream inputStream) throws Exception{
KeyStore keyStore = KeyStore.getInstance("pkcs12");
keyStore.load(inputStream, CUSTOMER_KS_PASSWORD.toCharArray());
//Save KeyStore in Internal Storage
FileOutputStream fos = context.openFileOutput(CUSTOMER_CERTIFICATE_STORE, Context.MODE_PRIVATE);
keyStore.store(fos, CUSTOMER_KS_PASSWORD.toCharArray());
fos.close();
}
/**
* Server certificate for SLL communication
* #param context
* #return HTTPS TrustStore
*/
public static KeyStore getServerKeystore(Context context){
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
// Load Keystore form internal storage
FileInputStream fis = context.openFileInput(SERVER_CERTIFICATE_STORE);
keyStore.load(fis, SERVER_KS_PASSWORD.toCharArray());
return keyStore;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Keystore not found.");
}
}
/**
* Load Server certificate for SLL communication
* #param context
* #param inputStream server trusted CAs
*/
public static void loadServerKeystore(Context context, InputStream inputStream) throws Exception{
// Load CAs from an InputStream
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca = cf.generateCertificate(inputStream);
inputStream.close();
// Create a KeyStore containing our trusted CAs
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry(SERVER_CERTIFICATE_ALIAS, ca);
// Save keystore to Internal Storage.
FileOutputStream fos = context.openFileOutput(SERVER_CERTIFICATE_STORE, Context.MODE_PRIVATE);
keyStore.store(fos, SERVER_KS_PASSWORD.toCharArray());
fos.close();
}
I use a SecretKey to encrypt sensitive data in my application. Currently I am storing my SecretKey in Base64 encoded format in DB or SharedPrefs which is not a safe place to store Secret on a rooted phone. Hence, I want to move my SecretKey to Android KeyStore. The problem I am facing is when I try this sample code from Google, it expects a PrivateKey instead of SecretKey. I couldn't figure out a way to store my SecretKey in KeyStore and fetch it for later use. I tried this:
private static void writeSecretKeyToKeystore(SecretKey secretKey, Context context) {
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
keyStore.setKeyEntry("Key", secretKeyEntry.getSecretKey().getEncoded(), null);
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
When I try above code, it throws an exception Operation not supported because encoding is unknown.
Any sample code would be of great help.
WRONG
java.security.KeyStore can store both symmetric and asymmetric keys. You just need to instantiate KeyStore.SecretKeyEntry passing it your SecretKey in the constructor and then use the KeyStore#setEntry method to save it:
keyStore.setEntry(
"key1",
new KeyStore.SecretKeyEntry(secretKey),
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockMode(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
To get it back out use:
SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null);
UPDATE
After some research I was surprised to find out, that AndroidKeyStore doesn't support symmetric keys. (see the discussion: https://groups.google.com/forum/#!topic/android-developers/gbmIRKRbfq8)
The work-around would be to encrypt your SecretKey and store it in SharedPreferences. Then store the key to decrypt your key in the Keystore. Here's an implementation using scytale.
public static String getBase64EncodedSecretKey(){
Store store = new Store(context);
Crypto crypto = new Crypto(Options.TRANSFORMATION_SYMMETRIC);
SecretKey key = store.getSymmetricKey("key_alias", null);
String encryptedData = PreferenceManager.getDefaultSharedPreferences(context).getString("myEncryptedSecretKey", "");
return crypto.decrypt(encryptedData, key);
}
public static void storeKey(String base64EncodedSecretKey){
Store store = new Store(context);
if (store.hasKey("key_alias")) {
store.deleteKey("key_alias");
}
SecretKey key = store.generateSymmetricKey("key_alias", null);
Crypto crypto = new Crypto(Options.TRANSFORMATION_SYMMETRIC);
String encryptedData = crypto.encrypt(base64EncodedSecretKey, key);
PreferenceManager.getDefaultSharedPreferences(context).edit().putString("myEncryptedSecretKey",encryptedData).apply();
}
// Usage:
//store SecretKey
byte[] encodedKey = secretKeyEntry.getSecretKey().getEncoded();
String base64EncodedKey = Base64.encodeToString(encodedKey);
storeKey(base64EncodedKey);
//get SecretKey
String base64EncodedKey = getBase64EncodedSecretKey();
byte[] encodedKey = Base64.decode(base64EncodedKey);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
im trying to implement SSL connection on android, but i have a problem when i try to load my keystore, but i when i call KeyStore.getInstance("RSA") i got this exception.
03-26 12:19:28.660: E/AndroidRuntime(6465): Caused by: java.lang.RuntimeException: java.security.KeyStoreException: java.security.NoSuchAlgorithmException: KeyStore RSA implementation not found
private KeyStore loadKeyStore() {
if (keyStore != null) {
Log.i("WSclient::KeyStore", " keyStore!=null");
return keyStore;
}
try {
Log.i("WSclient::KeyStore", " keyStore.getInstancel");
keyStore = KeyStore.getInstance("RSA");
Log.i("WSclient::KeyStore", " keyStore:: inputStream");
InputStream in = context.getResources().openRawResource(R.raw.file);
try {
Log.i("WSclient::KeyStore", " keyStore.load");
keyStore.load(in, KEYSTORE_PASSWORD.toCharArray());
} finally {
in.close();
}
return keyStore;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
The exception says it all. There is no such thing as an RSA keystore. There are JKS keystores, PCKS#11 keystores, WindowsMY keystores, all kinds of things. What kind yours is, only you know.
You can create a private/public key pair for the RSA algorithm as follows:
Calendar calendarValidityStart = Calendar.getInstance();
Calendar calendarValidityEnd = Calendar.getInstance();
calendarValidityEnd.add(Calendar.YEAR, 99);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias("MyKeyAlias")
.setSubject(new X500Principal("CN=" + "MyKeyAlias"))
.setSerialNumber(BigInteger.valueOf(1337))
.setStartDate(calendarValidityStart.getTime())
.setEndDate(calendarValidityEnd.getTime())
.build();
KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance(
"RSA",
"AndroidKeyStore");
kpGenerator.initialize(spec);
KeyPair keyPair = kpGenerator.generateKeyPair();
You can later retrieve the key pair from the KeyStore as follows:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.Entry keyStoreEntry = keyStore.getEntry(alias, null);
See the Android Developers BasicAndroidKeyStore Sample for more info.
Be sure to have
private KeyFactory keyStore;
keyStore must be KeyFactory type.
//keyStore = KeyStore.getInstance("RSA");
keyStore = KeyFactory.getInstance("RSA");
See this example:
How to use keystore in Java to store private key?