I would like like to check if the public key corresponds to the private key - is it correct.
There is also no provider called BC.
I have this implementation but i don't know what Utils.createFixedRandom() suppose to do.
I don't have such a library and method.
Besides if you have an raw implementation without java.security it would be awesome.
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Signature;
public class BasicDSAExample {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "BC");
keyGen.initialize(512, new SecureRandom());
KeyPair keyPair = keyGen.generateKeyPair();
Signature signature = Signature.getInstance("DSA", "BC");
signature.initSign(keyPair.getPrivate(), Utils.createFixedRandom() );
byte[] message = new byte[] { (byte) 'a', (byte) 'b', (byte) 'c' };
signature.update(message);
byte[] sigBytes = signature.sign();
signature.initVerify(keyPair.getPublic());
signature.update(message);
if (signature.verify(sigBytes)) {
System.out.println("pow");
} else {
System.out.println("nie");
}
}
}
You can't encrypt and decrypt using DSA, it's a digital signature algorithm. Digital signatures are created by encrypting a hash of the message using the signer's private key, so that it can be verified using their public key. But because it is hashed, the message cannot be recovered.
Following your edit:
If you have a private and a public key, the public key can be derived from the private one anyway, no need to use the key and verify anything. The private key contains all the information to construct a KeyPair, and then the getPublic() method will retrieve the equivalent public key. If you want to see if a given public key is correct, just compare with this.
Related
I'm developing an application that will store ECC public keys in a database. I used a existing code to generate the keys, but when I use the method to get the public key from a private key, I get two values (x and y coordinates) returned. Is there a java-ready function that allows me to generate a public key from these two values? I found a link explaining how to do it, but I did not understand how to use the method.
package test;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.security.*;
import java.security.spec.*;
public class test {
public static void main(String[] args) {
KeyPairGenerator kpg;
kpg = KeyPairGenerator.getInstance("EC","SunEC");
ECGenParameterSpec ecsp;
ecsp = new ECGenParameterSpec("secp256r1");
kpg.initialize(ecsp);
String key;
KeyPair kp = kpg.genKeyPair();
PrivateKey privKey = kp.getPrivate();
PublicKey pubKey = kp.getPublic();
key = pubKey.toString().substring(46,125).concat(pubKey.toString().substring(142,220));
}
}
I'm trying to validate the access token signature with my public key retrieved from an authentication server (OpenId).
The client get an access token from the same server and then request my Resource server API with it. Now I have to check its signature with the Spring Security library.
The access token has an "alg" : "RS256" attribute.
But the code below remains unsuccessful and I'm always getting the InvalidSignatureException...
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.InvalidSignatureException;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
public class JWTValidation {
private static final Logger logger = LoggerFactory.getLogger(JWTValidation.class);
private static final String PUBLIC_KEY_MODULUS = "qOYyKKnoUpXd2qIj8A0tdumWwnDbVjXOVaPfiX5lxBvYEtgWPLknf1Nftdk371a7f1jD8SFFDxXnj-PPFx8qoNETOITvbR12uvWmS1J36B5Uo_ViHp7dC-GaZG_EdafyK0rxRPvK8b37NPXWhTggbxCZhYaqJUMb1t0xogDadEyM95lZweEXrwsJNzoyXiGnPfsRgy32TjOOXIMZnAMoj-osYd2WawymkRV6cteo3f8KMT72_kp8oG-kGm1s3ZooEfI3_9Z2jHVGWQLUWbmZKIrvjuUo2dhmqWWsNyTO3RsF4qyrRCpmZNawDf_GsioBTZ3vfPF_T58moH7cJ50Byw";
private static final String PUBLIC_KEY_PUBLIC_EXPONENT = "AQAB";
//Public key =
// {
// "keys":[
// {
// "kty":"RSA",
// "use":"sig",
// "kid":"DQr-GCc8rH3y5fkAuo0iau-ue-s",
// "x5t":"DQr-GCc8rH3y5fkAuo0iau-ue-s",
// "e":"AQAB",
// "n":"qOYyKKnoUpXd2qIj8A0tdumWwnDbVjXOVaPfiX5lxBvYEtgWPLknf1Nftdk371a7f1jD8SFFDxXnj-PPFx8qoNETOITvbR12uvWmS1J36B5Uo_ViHp7dC-GaZG_EdafyK0rxRPvK8b37NPXWhTggbxCZhYaqJUMb1t0xogDadEyM95lZweEXrwsJNzoyXiGnPfsRgy32TjOOXIMZnAMoj-osYd2WawymkRV6cteo3f8KMT72_kp8oG-kGm1s3ZooEfI3_9Z2jHVGWQLUWbmZKIrvjuUo2dhmqWWsNyTO3RsF4qyrRCpmZNawDf_GsioBTZ3vfPF_T58moH7cJ50Byw",
// "x5c":["MIIDBDCCAfCgAwIBAgIQt1HpvYkM6oxJ1ZjbpW1fPTAJBgUrDgMCHQUAMBkxFzAVBgNVBAMTDkRhdGFEb29ycyBUZXN0MCAXDTE1MDQwMjIyMjQwM1oYDzIwNTAwMTAxMDYwMDAwWjAZMRcwFQYDVQQDEw5EYXRhRG9vcnMgVGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKjmMiip6FKV3dqiI/ANLXbplsJw21Y1zlWj34l+ZcQb2BLYFjy5J39TX7XZN+9Wu39Yw/EhRQ8V54/jzxcfKqDREziE720ddrr1pktSd+geVKP1Yh6e3QvhmmRvxHWn8itK8UT7yvG9+zT11oU4IG8QmYWGqiVDG9bdMaIA2nRMjPeZWcHhF68LCTc6Ml4hpz37EYMt9k4zjlyDGZwDKI/qLGHdlmsMppEVenLXqN3/CjE+9v5KfKBvpBptbN2aKBHyN//Wdox1RlkC1Fm5mSiK747lKNnYZqllrDckzt0bBeKsq0QqZmTWsA3/xrIqAU2d73zxf0+fJqB+3CedAcsCAwEAAaNOMEwwSgYDVR0BBEMwQYAQgtiIGHLzFEskZSe/65EOTqEbMBkxFzAVBgNVBAMTDkRhdGFEb29ycyBUZXN0ghC3Uem9iQzqjEnVmNulbV89MAkGBSsOAwIdBQADggEBADtIlf41MLeGwjTbhJS88stZEBhEexxXNJDlW92GKPVv0JJWD/5m8tfADzXOgP65rTyQ4lTGOFFRYQu0ajMYAzggqJTmU1rMrHxuVwLfJ3OpSOc9UZBs2gW/IUZFvSugMKNboTsfTPgpsHK1ag68NKvR/V209zYZd6A7zisGgUr2Oc5jNEj7lSQY6pME2ZXU0YppC6Dctj8XHkTO9Ji9vDj+iGoS4+RvHZ3cDr5YUbOKSooOAZ/kjqtm+VK2jdjdLrkduz/24NKIxEXQqhmM28f8kh5Wc2ilaMya9pxQZpTWk7sjOBkZCcw24tx6UqpSTsV/XnnTmJMIhgXFJXWnXFc="]
// }
// ]
// }
//Access Token = base64url encoded String
public boolean verifySignature(String accessToken){
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Base64 decoder = new Base64(true);//URL-safe Base64 decoder
BigInteger modulus = new BigInteger(decoder.decode(PUBLIC_KEY_MODULUS.getBytes()));
BigInteger publicExponent = new BigInteger(decoder.decode(PUBLIC_KEY_PUBLIC_EXPONENT.getBytes()));
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);
PublicKey newPublicKey = keyFactory.generatePublic(spec);
RsaVerifier verif = new RsaVerifier((RSAPublicKey) newPublicKey, "SHA256withRSA");
JwtHelper.decodeAndVerify(accessToken, verif);
} catch (InvalidSignatureException e){
logger.info(e.getMessage());
return false;
} catch (Exception e){
logger.info(e.getMessage());
return false;
}
return true;
}
}
I also tried to use the online tool jwt.io but I've not been able to make it work (the signature remains invalid)
And for the other one (tool_jwt), the only way to have a valid signature is to choose the "default X.509 certificate RSA" with comments around my public key "x5c" value :
-----BEGIN CERTIFICATE-----
MIIDBDCCAfCgAwIBAgIQt1HpvYkM6oxJ1ZjbpW1fPTAJBgUrDgMCHQUAMBkxFzAVBgNVBAMTDkRhdGFEb29ycyBUZXN0MCAXDTE1MDQwMjIyMjQwM1oYDzIwNTAwMTAxMDYwMDAwWjAZMRcwFQYDVQQDEw5EYXRhRG9vcnMgVGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKjmMiip6FKV3dqiI/ANLXbplsJw21Y1zlWj34l+ZcQb2BLYFjy5J39TX7XZN+9Wu39Yw/EhRQ8V54/jzxcfKqDREziE720ddrr1pktSd+geVKP1Yh6e3QvhmmRvxHWn8itK8UT7yvG9+zT11oU4IG8QmYWGqiVDG9bdMaIA2nRMjPeZWcHhF68LCTc6Ml4hpz37EYMt9k4zjlyDGZwDKI/qLGHdlmsMppEVenLXqN3/CjE+9v5KfKBvpBptbN2aKBHyN//Wdox1RlkC1Fm5mSiK747lKNnYZqllrDckzt0bBeKsq0QqZmTWsA3/xrIqAU2d73zxf0+fJqB+3CedAcsCAwEAAaNOMEwwSgYDVR0BBEMwQYAQgtiIGHLzFEskZSe/65EOTqEbMBkxFzAVBgNVBAMTDkRhdGFEb29ycyBUZXN0ghC3Uem9iQzqjEnVmNulbV89MAkGBSsOAwIdBQADggEBADtIlf41MLeGwjTbhJS88stZEBhEexxXNJDlW92GKPVv0JJWD/5m8tfADzXOgP65rTyQ4lTGOFFRYQu0ajMYAzggqJTmU1rMrHxuVwLfJ3OpSOc9UZBs2gW/IUZFvSugMKNboTsfTPgpsHK1ag68NKvR/V209zYZd6A7zisGgUr2Oc5jNEj7lSQY6pME2ZXU0YppC6Dctj8XHkTO9Ji9vDj+iGoS4+RvHZ3cDr5YUbOKSooOAZ/kjqtm+VK2jdjdLrkduz/24NKIxEXQqhmM28f8kh5Wc2ilaMya9pxQZpTWk7sjOBkZCcw24tx6UqpSTsV/XnnTmJMIhgXFJXWnXFc=
-----END CERTIFICATE-----
So I don't know what to do now, which public key attribute should I use, and how to make it work ?
Thanks a lot for your help :)
I had the use the x509 key spec in addition to the RSA key spec
RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(modulusBytes), new BigInteger(exponentBytes));
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey key = factory.generatePublic(spec);
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(key.getEncoded());
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pubKey64 = kf.generatePublic(X509publicKey);
This worked for both the auth0 and jwt.io libraries
To validate the signature online with jwt.io, you just need to put there the following json as a public key:
{
"kty":"RSA",
"kid":"DQr-GCc8rH3y5fkAuo0iau-ue-s",
"e":"AQAB",
"n":"qOYyKKnoUpXd2qIj8A0tdumWwnDbVjXOVaPfiX5lxBvYEtgWPLknf1Nftdk371a7f1jD8SFFDxXnj-PPFx8qoNETOITvbR12uvWmS1J36B5Uo_ViHp7dC-GaZG_EdafyK0rxRPvK8b37NPXWhTggbxCZhYaqJUMb1t0xogDadEyM95lZweEXrwsJNzoyXiGnPfsRgy32TjOOXIMZnAMoj-osYd2WawymkRV6cteo3f8KMT72_kp8oG-kGm1s3ZooEfI3_9Z2jHVGWQLUWbmZKIrvjuUo2dhmqWWsNyTO3RsF4qyrRCpmZNawDf_GsioBTZ3vfPF_T58moH7cJ50Byw"
}
I am totally new to security and signature verification and so far I couldn't find a place which explained the basics of signature verification. I need to verify the signature of a file by obtaining the public key from the appropriate certificate available from certificate store. the tutorial in Java (https://docs.oracle.com/javase/tutorial/security/apisign/versig.html) doesn't teach how to obtain a certificate from the trusted certificate store and verify using that. I went through Bouncy castle WIKI http://www.bouncycastle.org/wiki/display/JA1/BC+Version+2+APIs but its not really explanatory for a beginner. How do I do this? Given a signed file, how can I check for its public key from the certificate store and verify if its the right person who has sent the file? Please advice.
Because you did not provide what build management you use, I assume it will be Maven.
First, include BouncyCastle in your dependency
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.53</version>
</dependency>
After that, you need to make a util class that you will be using for sign or verify the certificate. Something like this:
package your.pack.location;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* Author: harunalfat
*/
public class SignatureUtils {
private static final Logger log = LogManager.getLogger(SignatureUtils.class);
public static String sign(String plainText, PrivateKey privateKey) throws Exception {
byte[] data = plainText.getBytes("ISO-8859-1");
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initSign(privateKey);
signature.update(data);
return Base64.toBase64String(signature.sign());
}
public static boolean verify(String plainText, String signString, PublicKey publicKey) throws Exception{
byte[] data = plainText.getBytes("ISO-8859-1");
Signature signature = Signature.getInstance("SHA1WithRSA", "BC");
signature.initVerify(publicKey);
signature.update(data);
byte[] signByte = Base64.decode(signString);
return signature.verify(signByte);
}
private static PemObject getPemObjectFromResource(String fileLocation) throws IOException {
Resource resource = new ClassPathResource(fileLocation);
InputStream is = resource.getInputStream();
PemObject pemObject = new PemReader(new InputStreamReader( is )).readPemObject();
return pemObject;
}
private static X509EncodedKeySpec getPubKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {
PemObject pemObject = getPemObjectFromResource(fileLocation);
byte[] data = pemObject.getContent();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(data);
return keySpec;
}
private static PKCS8EncodedKeySpec getPriKeySpec(String fileLocation) throws IOException, NoSuchAlgorithmException {
PemObject pemObject = getPemObjectFromResource(fileLocation);
byte[] data = pemObject.getContent();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);
return keySpec;
}
public static PublicKey getPublicKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
KeySpec keySpec = getPubKeySpec(fileLocation);
return kf.generatePublic(keySpec);
}
public static PrivateKey getPrivateKey(String fileLocation) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
KeySpec keySpec = getPriKeySpec(fileLocation);
return kf.generatePrivate(keySpec);
}
}
And then you will use it like this
package your.another.pack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import static org.junit.Assert.assertTrue;
/**
* Author: harunalfat
*/
public class SignatureUtilsTest {
private static final Logger log = LogManager.getLogger(SignatureUtilsTest.class);
private static final String PLAIN = "attack at dawn";
#Test
public void testSignAndVerify() throws Exception {
Security.addProvider(new BouncyCastleProvider()); // <-- IMPORTANT!!! This will add BouncyCastle as provider in Java Security
PrivateKey privateKey = SignatureUtils.getPrivateKey("key/private2.pem"); // This is located on src/main/resources/key/private2.pem
PublicKey publicKey = SignatureUtils.getPublicKey("key/public2.pem"); // This is located on src/main/resources/key/public2.pem
// In this example, I use junit test, so it will be on src/test/resources/...
log.info("Private Key : "+Base64.encodeBase64String(privateKey.getEncoded()));
log.info("Public Key : "+Base64.encodeBase64String(publicKey.getEncoded()));
String sign = SignatureUtils.sign(PLAIN, privateKey);
log.info("Plain String : "+PLAIN);
log.info("Sign : "+sign);
boolean result = SignatureUtils.verify(PLAIN,sign, publicKey);
log.info("Result : "+result);
assertTrue(result);
}
}
Of course, you can change the Signature instance with another Algorithm. In my case I use "SHA1WithRSA", but you get the point right?
With this, someone will encrypt their data using their private key, and send it to you. After that, you will verify the data using the public key they give.
In example, Bob send to you message about money amount he sent to you ($5000), and sign it using their private key, become encrypted. When the data arrived to you, you know Bob supposed to send $5000, then you verify the encrypted data with text $5000 and public key Bob share, but is it really $5000 OR does it comes from Bob?
If the data has been changed, OR when someday you ask for some Money to Bob, but the message tapped by someone else and s/he send you the amount message with private key other than Bob's, you will know.
Feel free to ask :)
I have a symmetric Key in my JKS (Java Key Store) file, I want to wrap my private key with a symmetric key.
Again I am using wrappedBytes to PrivateKey Object. And finally I want the KeyPair Object.
The below code gives the following error message:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=125, too big.**
public KeyPair wrapPrivateKeyWithSymmetricKey(KeyPair keyPair) {
try {
PrivateKey priv = keyPair.getPrivate();
SecretKey symmetricKey = "bjksabfkasdbgvkasbvkkj";//symmetricKey from jks file
//wrapping Private Key
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.WRAP_MODE, symmetricKey);
byte[] wrappedKey = cipher.wrap(priv);
//wrappedKey bytes to PrivateKey Object
KeyFactory keyFactory = KeyFactory.getInstance(priv.getAlgorithm());
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(wrappedKey);
PrivateKey privateKey2 = keyFactory.generatePrivate(privateKeySpec); //above Error Throwing in this line
return new KeyPair(keyPair.getPublic(), privateKey2);;
}
How can I solve this?
In your example, wrappedBytes isn't in a PKCS #8 format. It's simply some AES encrypted blocks—essentially random data—with no encoded structure.
If you want to create an encrypted PKCS #8 (formally, EncryptedPrivateKeyInfo) you'll need a library that handles that. The built-in API you are trying to use only handles its clear-text payload, PrivateKeyInfo (as described in its documentation).
There isn't much to the wrapper, and you could write the necessary DER coding yourself, or use a library like BouncyCastle.
Here's code, using BouncyCastle to encoded and decode the EncryptyedPrivateKeyInfo structure. The useless class provided by the JCE doesn't work, because of poor handling of the key encryption algorithm identifier and its parameters.
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
final class PKCS8
{
private static final ASN1ObjectIdentifier AES = ASN1ObjectIdentifier.getInstance(NISTObjectIdentifiers.id_aes128_CBC);
static RSAPublicKey toPublic(RSAPrivateCrtKey pvt)
throws GeneralSecurityException
{
RSAPublicKeySpec pub = new RSAPublicKeySpec(pvt.getModulus(), pvt.getPublicExponent());
KeyFactory f = KeyFactory.getInstance("RSA");
return (RSAPublicKey) f.generatePublic(pub);
}
static byte[] encrypt(SecretKey secret, PrivateKey pvt)
throws Exception
{
Cipher enc = Cipher.getInstance("AES/CBC/PKCS5Padding");
enc.init(Cipher.WRAP_MODE, secret);
ASN1Encodable params = new DEROctetString(enc.getIV());
AlgorithmIdentifier algId = new AlgorithmIdentifier(AES, params);
byte[] ciphertext = enc.wrap(pvt);
return new EncryptedPrivateKeyInfo(algId, ciphertext).getEncoded();
}
static PrivateKey decrypt(SecretKey secret, byte[] pkcs8)
throws Exception
{
EncryptedPrivateKeyInfo info = new PKCS8EncryptedPrivateKeyInfo(pkcs8).toASN1Structure();
AlgorithmIdentifier id = info.getEncryptionAlgorithm();
byte[] iv = ((ASN1OctetString) id.getParameters()).getOctets();
Cipher dec = Cipher.getInstance("AES/CBC/PKCS5Padding");
dec.init(Cipher.UNWRAP_MODE, secret, new IvParameterSpec(iv));
return (PrivateKey) dec.unwrap(info.getEncryptedData(), "RSA", Cipher.PRIVATE_KEY);
}
}
Currently, the only way I know to retrieve the administrator password from a newly created EC2 windows instance is through the AWS management console. This is fine, but I need to know how to accomplish this via the Java API - I can't seem to find anything on the subject. Also, once obtained, how do I modify the password using the same API?
The EC2 API has a call "GetPasswordData" which you can use to retrieve an encrypted block of data containing the Administrator password. To decrypt it, you need 2 things:
First, the private key. This is the private half of the keypair you used to instantiate the instance. A complication is that normally Amazon uses keys in PEM format ("-----BEGIN"...) but the Java Crypto API wants keys in DER format. You can do the conversion yourself - strip off the -----BEGIN and -----END lines, take the block of text in the middle and base64-decode it.
Second, the encryption parameters. The data is encrypted with RSA, with PKCS1 padding – so the magic invocation to give to JCE is: Cipher.getInstance("RSA/NONE/PKCS1Padding")
Here's a full example (that relies on BouncyCastle, but could be modified to use a different crypto engine)
package uk.co.frontiertown;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.GetPasswordDataRequest;
import com.amazonaws.services.ec2.model.GetPasswordDataResult;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import javax.crypto.Cipher;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
public class GetEc2WindowsAdministratorPassword {
private static final String ACCESS_KEY = "xxxxxxxxxxxxxxxxxxxx";
private static final String SECRET_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
private static final String PRIVATE_KEY_MATERIAL = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIEowIBAAKCAQEAjdD54kJ88GxkeRc96EQPL4h8c/7V2Q2QY5VUiJ+EblEdcVnADRa12qkohT4I\n" +
// several more lines of key data
"srz+xXTvbjIJ6RL/FDqF8lvWEvb8uSC7GeCMHTznkicwUs0WiFax2AcK3xjgtgQXMgoP\n" +
"-----END RSA PRIVATE KEY-----\n";
public static void main(String[] args) throws GeneralSecurityException, InterruptedException {
Security.addProvider(new BouncyCastleProvider());
String password = getPassword(ACCESS_KEY, SECRET_KEY, "i-XXXXXXXX", PRIVATE_KEY_MATERIAL);
System.out.println(password);
}
private static String getPassword(String accessKey, String secretKey, String instanceId, String privateKeyMaterial) throws GeneralSecurityException, InterruptedException {
// Convert the private key in PEM format to DER format, which JCE can understand
privateKeyMaterial = privateKeyMaterial.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
privateKeyMaterial = privateKeyMaterial.replace("-----END RSA PRIVATE KEY-----", "");
byte[] der = Base64.decode(privateKeyMaterial);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(der);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// Get the encrypted password data from EC2
AWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
AmazonEC2Client client = new AmazonEC2Client(awsCredentials);
GetPasswordDataRequest getPasswordDataRequest = new GetPasswordDataRequest().withInstanceId(instanceId);
GetPasswordDataResult getPasswordDataResult = client.getPasswordData(getPasswordDataRequest);
String passwordData = getPasswordDataResult.getPasswordData();
while (passwordData == null || passwordData.isEmpty()) {
System.out.println("No password data - probably not generated yet - waiting and retrying");
Thread.sleep(10000);
getPasswordDataResult = client.getPasswordData(getPasswordDataRequest);
passwordData = getPasswordDataResult.getPasswordData();
}
// Decrypt the password
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] cipherText = Base64.decode(passwordData);
byte[] plainText = cipher.doFinal(cipherText);
String password = new String(plainText, Charset.forName("ASCII"));
return password;
}
}
ObDisclosure: I originally answered this on a blog posting at http://www.frontiertown.co.uk/2012/03/java-administrator-password-windows-ec2-instance/
You can create an instance, set the password and then turn it back into an image. Effectively setting a default password for each instance you create. Wouldn't this be simpler?
Looks like you are looking for the following parts of the API: GetPasswordDataRequest and GetPasswordDataResult
You can also create a Image with default user name and Password setup on that Image.And then launch all instances with that image id..so that you dont need to create and retrieve password evry time..just launch your instance rdp that launched instance with definde credntials in Image. I am doing same.And its perfectly working for me.