I'm working on project which collect data from some government portal.
To obtain valid data I had to make request containing some exact xml data.
The xml data had also to contain public key of my certificate. The the portal then encrypts
the returned data. Having private key of the certificate I am then able to decrypt returned data. So far so good, it's working.
But how am I getting the public key of my certificate for the xml? So far manually.
I found the certificate among other personal ones in Chrome browser.
Exported it into file, without private key, X.509, coding Base-64 (CER).
Then opened the exported file in the text editor, removed '-----BEGIN CERTIFICATE-----'
and '----END CERTIFICATE-----''and the rest put into XML
This all I need to repeat by java code (BouncyCastle library ?). I think it will be easy,
but the examples are scarce.
Thanks.
I finally googled the solution, the class JcaPEMWriter (BouncyCastle library) did the trick. Now the output is the same as exported manually.
public static String convertCertificateToPEM(X509Certificate signedCertificate) throws IOException {
StringWriter signedCertificatePEMDataStringWriter = new StringWriter();
JcaPEMWriter pemWriter = new JcaPEMWriter(signedCertificatePEMDataStringWriter);
pemWriter.writeObject(signedCertificate);
pemWriter.close();
return signedCertificatePEMDataStringWriter.toString();
}
Related
Context: I am trying to download and save Azure Vault keys on a container - with the purpose of using them later to encrypt or decrypt content.
I am using Java with azure-identity 1.7.1 and com.azure.security.keyvault.keys libraries.
The problem is that I cannot figure out how to download the private portion of the key. When trying to use the key to decrypt content I get the following error
java.lang.IllegalArgumentException: Private portion of the key not available to perform decrypt operation
Following is the code used to save the key to disk. How can one modify the code to get both the public and the private portion of the key?!
DefaultAzureCredential defaultCredential = new DefaultAzureCredentialBuilder().build();
KeyClient keyClient = new KeyClientBuilder()
.vaultUrl("https://<MY VAULT>.vault.azure.net/")
.credential(defaultCredential)
.buildClient();
JsonWebKey jsonWebKey = keyClient.getKey("<MY KEY>").getKey();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(jsonWebKey);
try (PrintWriter writer = new PrintWriter("my-key.json")) {
writer.print(json);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Is the private portion of the key available?
Should the key be created in a certain way to make that available in the first place?
Note: for Certificates one can download the associated secret, base64 decode it and save it as PFX, and that will includes the highly sought-after private key! Also, the Azure portal interface includes an equivalent "download PFX" button. Nothing for keys in the vault??!
I would like to get the email address and expire date to a S/MIME certificate based on it's public key. Is this aproach even possible? Or am I totally wrong? Can I decrypt the public key to get these kind of data via java?
I searched in google, read the wiki pages and read about an oracle s/mime project. But it doesn't seam like its possible. Are those data only availabe in the csr??
Thanks in advance
I'm amazed this isn't a dupe, but I couldn't find a good one.
Although Bouncy is fine and has many features if you want to use it, core Java can handle X.509 certificates since forever. For a cert in a file (or anything that can be accessed as a Stream) in either PEM or DER format (although the javadoc isn't clear on that) all you need is CertificateFactory:
CertificateFactory fact = CertificateFactory.getInstance("X.509");
// from a real file
InputStream is = new FileInputStream ("filename");
Certificate cert = fact.generateCertificate(is);
is.close(); // or use try-resources to do automatically
// from an alternate/custom filesystem, such as a ZIP
Path p = Paths.get("somespecification"); // or any other creation of a Path
InputStream is = Files.newInputStream(p); // add open options if needed
// same as before
// from the classpath (usually a JAR)
InputStream is = ClassLoader /*or any Class<?> object*/ .getResourceAsStream("name");
// same as before
// from a byte[] in memory
InputStream is = new ByteArrayInputStream (bytearray);
// same as before, except don't really need to close
// you get the idea
Although JCA APIs like this one are defined to allow a lot of extension, reading an X.509 cert will actually give you not just Certificate but subclass X509Certificate from which .getNotAfter() gives the expiration date-time directly. The email address if present (which isn't required by X.509 certs in general, but should always be the case in a cert used for S/MIME) will usually be an attribute in the subject name, which actually has internal structure that Java doesn't let you get at directly so you need to:
String x500name = ((X509Certificate)cert).getSubjectX500Principal()) .toString();
// simple case: no multivalue RDN, no reserved chars ,+="<>\;# or extra spaces
for( String attr : x500name.split(", ") )
if( attr.startsWith("EMAILADDRESS=") )
... use attr.substring(13) ...
// other cases require slightly more complicated parsing
Note there is no encryption at all in X.509, and thus no actual decryption, although many people use 'decrypt' to describe anything unfamiliar not an actual cipher.
File file = new File(fileName);
FileReader fileReader = new FileReader(file);
PEMParser pemParser = new PEMParser(fileReader);
X509CertificateHolder caCertificate = (X509CertificateHolder) pemParser.readObject();
I have a program to sign and verify text and zip files using pkcs#7 and bouncycastle.
Am writing the following string into both text and zip files( which contains base64 encoded original data, SignedBytes and Certificate data) :
String finalmsg="<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n" +
"<Envelope>\n" +" <OrgContent>"+new String(Base64.encode(contentbytes))+"</OrgContent>\n"+" <Signature>"+new String(Base64.encode(signedBytes))+"</Signature>\n"+" <Certificate>"+
new String(Base64.encode(keyStore.getCertificate("CertName").getEncoded()))+"</Certificate>\n"+"</Envelope>";
Am able to verify my text file perfectly after signing. Also am able to verify my zip file but am not able to extract the zip file ( am getting unexpected end of zip file error)
Below is the code am using to write my signed message into the files :
if(file.getName().contains(".zip")) {
byte[] b = finalmsg.getBytes(StandardCharsets.UTF_8);
try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(address+"SIGVERFILES/s2/"+name), 4096)) {
out.write(b);
}
} else {
FileWriter fw = new FileWriter(address+"SIGVERFILES/s2/"+name,true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(finalmsg);
bw.close();
}
Also am able to verify and unzip successfully zip files signed by other parties. So my verification code is fine. I think somethings wrong with the way am writing the zip file.
Please dont mind the indentation and request you to help me try to find out what am doing wrong here?
Please let me know if anymore code snippets are required.
You can't just write a XML string into a file, rename it to "whatever.zip", and expect the result to be a valid zip file. Zip is a binary file format with its own constraints, one of them being the magic number starting with "PK" at the beginning of the file.
Exchanging signed data also has its own constraints, and PKCS#7 SignedData is also a normalized format.
To make your life easier, BouncyCastle provides helper classes to generate valid, properly wrapped signed data. Check out their documentation and examples here and here.
You will want to decide between generating an attached or detached signature : with an attached signature, the ASN.1 structure contains the signed message, so you can read validate the signature and read the payload from the same data block (example : RSA certificates). With a detached signature, it'll be up to you to transmit the data and its signature separately (but the recipiend will need both in order to verify the signature - example : signed files available for download on a public FTP server). Usually the question is answered simply by asking yourself if the recipient may want to use the payload without verifying its signature first, or not.
I have a JAR file and it depends on 5 different text files. The JAR file read the text files and give the result. The only problem I have is that I want to hide text files so that no one can see it. Kindly suggest me how should I add these text files in-to the JAR package. If someone knows JAR-TO-EXE tool so that the text files are hided in-to the EXE then it is acceptable too.
I suggest you look into Serialization as a possible solution, here's a link.
http://www.tutorialspoint.com/java/java_serialization.htm
I'm not 100% sure it isnt possible to reconstruct your data anyway but... the content of the file will definently be gibberish when you open it (even if you don't wanna use it for this learn it anyways its very useful).
EDIT: I wanted to elaborate abit so you know what it basically is (if you don't)... imagine you have an arraylist containing objects (the data that you need to save, like your own employee class or whatever. Wih serialization you can basically serialize that list to a file and when you wanna load the data simply deserialize it back. The file with the saved data will contain gibberish to anyone who opens it. It's actually alot easier than working with an average file, where you usually have to handle reading each line etc. also remember you have to implement Serializable interface in the classes you need to do it with.
Made you a simple example, below I'm using an extremely simple class called testing which only contains a name:
public class Testing implements Serializable {
private String name;
public Testing(String name) {
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now to serialize an object of this class, remember you can do this with an arraylist of the objects aswell but it won't work in a static context! So you can't test it in a main method fx.
File file = new File("test.dat");
if (!file.exists()) file.createNewFile();
try {
ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("test.dat"));
out.writeObject(new Testing("testobject"));
} catch(Exception ex) {}
try {
ObjectInputStream in = new ObjectInputStream( new FileInputStream("test.dat"));
Testing loadedObject = (Testing) in.readObject();
System.out.println( loadedObject.getName() );
} catch(Exception ex){}
The above code can be tested within a main method if you wanna see it in action, just copy paste it and import the stuff needed.
EDIT: Should mention that I read it is possible to use a simple but secure encryption method by using a wrapper class before serializing the object. But you will have to read up on that, though imo it would be a very elegant solution to use.
You can 'hide' the files in the jar, but they will still be accessible. Just unzipping the jar will provide access to its contents. If these documents are in anyway 'sensitive' I would suggest looking at encrypting them.
Cryptography itself is a broad subject that requires real understanding to create a secure solution, but the following has a basic example of encrypting and decrypting data using java.
http://www.software-architect.net/articles/using-strong-encryption-in-java/introduction.html
EDIT
The link suggests using the following:
The same code to generate the 'aesKey':
String key = "Bar12345Bar12345"; // 128 bit key
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
To encrypt a string:
// encrypt the text
String toEncrypt = "Your text.";
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encryptedBytes = cipher.doFinal(toEncrypt.getBytes());
String encrypted = new String(encryptedBytes);
To decrypt a string:
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(encrypted.getBytes()));
The stored text in the file will be completely unintelligible. There are other things to consider; for example if you store the key in a class it will be possible to extract it. But with all security measures, the complexity of creating it has to balanced against the difficulty involved in working against it. This level is ultimately dependant on the nature of the information you are securing.
If you simply want to package the text files inside the jar, and the secruity of them is not an issue, see the following (assuming you are using eclipse):
How to package resources in Jar properly
How to display details of the subject in a certificate (DER format ie .cer file) in java ? eg: email, country, Name or seperate OIDs etc.
Reading a certificate could be done from the above code. Will work in Android as well. Thank you GreyBeardedGeek. But to more elaborate on it (As curious requested), if you display the subject details by using methods getSubjectDN() or cert.getSubjectX500Principal().getname() it will display the whole details. Some may be encoded. I believe it ASN1.(not sure). What I need is to extract only the information I need. For an example please refer the output of the code for a sample certificate I had created. using method - cert.getSubjectX500Principal().getname() Subject Name 2.5.4.5=#130d4e2d61626c652f49542f303130,2.5.4.72=#1308456e67696e656572,2.5.4.41=#13104e7577616e20446520416c6d65696461,1.2.840.113549.1.9.1=#16106e7577616e406e2d61626c652e62697a,OU=Information Technology,O=N-able Pvt Ltd\ ,ST=Western,C=LK
2.5.4.5 is an OID (Object Identifier) which is encoded.
Using method - getSubjectDN()
OID.2.5.4.5=N-able/IT/010, OID.2.5.4.72=Engineer, OID.2.5.4.41=Nuwan De Almeida, OID.1.2.840.113549.1.9.1=#16106E7577616E406E2D61626C652E62697A, OU=Information Technology, O="N-able Pvt Ltd ", ST=Western, C=LK
Here also some information is encoded eg: email address.
So coming back to my question , how can we extract information(not encoded) separately based on the OID. Further if you install the certificate in windows OS you could view the subject information correctly.What I need is a code to get the OID value information passing the OID in java, to extract subject details separately.
Thank you again in advance.
Look into the Bouncy Castle ASN.1 parsing libraries and especially X500Name. It can parse a distinguished name (DN) into its parts (CN, O, etc.).
http://www.bouncycastle.org/docs/docs1.5on/index.html
The following code (no error handling included) will produce an instance of X509Certificate from the .cer file. You can then use that object's methods to inspect the properties of the certificate. The code is generic java, but should work in Android.
X509Certificate cert = null;
FileInputStream fis = null;
ByteArrayInputStream bais = null;
String source = "certificate.cer";
String certType = "X.509"
fis = new FileInputStream(source);
byte[] value = new byte[fis.available()];
fis.read(value);
bais = new ByteArrayInputStream(value);
java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance(certType);
cert = (X509Certificate)cf.generateCertificate(bais);