How do you print a PKCS10CertificationRequest as a String? - java

Is there a way to print the CSR generated with PKCS10CertificationRequest class? I am struggling to see the generated request.
PKCS10CertificationRequest certRequest = new PKCS10CertificationRequest(fromByteArray);
System.out.println("CSR string = "+certRequest.toString());
System.out.println("CSR Subject Name = "+certRequest.getSubject().toString());
System.out.println("CSR Subject PubkeyInfo = "+certRequest.getSubjectPublicKeyInfo().toString());

Hope this can help:
PemObject pemObject = new PemObject("CERTIFICATE REQUEST", certRequest.getEncoded());
StringWriter str = new StringWriter();
PEMWriter pemWriter = new PEMWriter(str);
pemWriter.writeObject(pemObject);
pemWriter.close();
str.close();
System.out.println(str);

Related

How to encrypt Credentials object - Cipher.doFinal, SealedObject, or CipherOutputStream?

I need to encrypt a set of user credentials and send it to a SOAP web service. The following code snippet (I think it's C#) is provided in the documentation, and my Java code is based on it.
private string Encrypt256(string text, AesCryptoServiceProvider aes)
{
// Convert string to byte array
byte[] src = Encoding.Unicode.GetBytes(text);
// encryption
using (ICryptoTransform encrypt = aes.CreateEncryptor())
{
byte[] dest = encrypt.TransformFinalBlock(src, 0, src.Length);
// Convert byte array to Base64 strings
return Convert.ToBase64String(dest);
}
}
...
Credentials credential = new Credentials();
credential.UserName = "username";
credential.Password = "password";
credential.ClientUtcTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ", System.Globalization.CultureInfo.InvariantCulture);
//--Serialize credential
XmlSerializer serializer = new XmlSerializer(credential.GetType());
string xmlCredential = string.Empty;
using (var stringwriter = new System.IO.StringWriter())
{
serializer.Serialize(stringwriter, credential);
xmlCredential = stringwriter.ToString();
}
//--Encrypt credential with AES256 symmetric
String encryptedCredential = Encrypt256(xmlCredential, aesServiceProvider);
...
The following is my Java code.
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(256);
SecretKey sk = kg.generateKey();
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, sk);
Credentials cred = new UsernamePasswordCredentials("username", "password");//no need for time field?
String eCred = Base64.encodeBase64String(aesCipher.doFinal(objectToByteArray(cred)));
...
private byte[] objectToByteArray(Object obj) {
byte[] bytes = null;
try (
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
) {
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray();
}
catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
Then I came across SealedObject and CipherOutputStream. I tried writing code snippets for those.
Using SealedObject
// slight change here; cred must implement Serializable
UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username", "password");
// same as above except for the following two lines
SealedObject so = new SealedObject(cred, aesCipher);
String eCred = Base64.encodeBase64String(objectToByteArray(so));
Using CipherOutputStream
Credentials cred = new UsernamePasswordCredentials("username", "password");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(bos, aesCipher);
cos.write(objectToByteArray(cred));
cos.close();
String eCred = Base64.encodeBase64String(bos.toByteArray());
For all three code snippets, is the code correct? Considering that this code will be called frequently, which approach is the most efficient?

Read/Write Certificate Signing Request on Android (spongycastle)

I try to write code on Android to generate RSA key-pair and then generate Certificate Request file (.csr) like this image below:
First I use spongycastle lib to generate Key Pair (public key and private key)
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024,new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
publicKey = keyPair.getPublic();
privateKey = keyPair.getPrivate();
Then I use CSRHelper class I found on this link to generate: byte CSRder[]:
byte CSRder[] = csr.getEncoded();
I write code to write byte[] to file:
File file;
FileOutputStream outputStream;
try
{
file = new File(getCacheDir(),"csr.txt");
outputStream = new FileOutputStream(file);
outputStream.write(CSRder);
outputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
Final I write code to read file again:
BufferedReader input = null;
File file = null;
try {
file = new File(getCacheDir(), "csr.txt"); // Pass getFilesDir() and "MyFile" to read file
input = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
String line;
StringBuffer buffer = new StringBuffer();
while ((line = input.readLine()) != null) {
buffer.append(line);
}
Log.d(TAG, buffer+"");
} catch (IOException e) {
e.printStackTrace();
}
But my logcat show unreadable character.
07-21 13:48:35.163 16157-16157/com.example.napoleon.test_2 D/MainActivity: 0��0���0;10Unapoleon.com10UAralink10UOrgUnit0��0 *�H��������0�������Qt��G�]�ܪ�0�'�I^�Q��[�r5ڢ_!|������ZC��~<��*o�?�d+-����)��V�<߹��m��(��ѐxDcx��NhƬF��Ҵvq+���0�Iq�-Eoe,���"0 *�H�� 100U�0�0 *�H���������YPT3��?��P5MY��hs)��$1Gv�r_��76ߞ;���ҽ�޼ t�kI�I��Z��tg����O�W��Gt�=���V���#G1�$z�$�V����_^7_x�?�0�׵#�;��f?�
How to write this csr byte to file and read again?
CSRder is binary, you can not read it as string because it has non-printable characters.
Since you require PEM format for .csr file, it is needed to convert the binary content to base64 and add the PEM header and footer
----BEGIN CERTIFICATE REQUEST-----
(base64)
----END CERTIFICATE REQUEST-----
This can be done manually or using spongycastle's PEMWriter
StringWriter writer = new StringWriter();
PemWriter pemWriter = new PemWriter(writer);
pemWriter.writeObject(new PemObject("CERTIFICATE REQUEST", CSRder));
pemWriter.flush();
pemWriter.close();
String csrPEM = writer.toString();
After this, you can save csrPEM as string file.

How to serialize PKCS10CertificationRequest in BouncyCastle to send it over network?

I have been trying to serialize the object PKCS10CertificationRequest for a while now. I figured the right way to do it is to create an ASN1Primitive class, send it over the network, then deserialize it. However, there seems to be only serialization into ASN1, but there seems to be no deserialization from ASN1, and I don't want to manually parse and reconstruct the Request. What should I do? My code so far is
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SC");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
System.out.println("Private: " + kp.getPrivate());
System.out.println("Public: " + kp.getPublic());
X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
x500NameBld.addRDN(BCStyle.C, "AU");
x500NameBld.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
x500NameBld.addRDN(BCStyle.L, "Melbourne");
x500NameBld.addRDN(BCStyle.ST, "Victoria");
x500NameBld.addRDN(BCStyle.EmailAddress, "feedback-crypto#bouncycastle.org");
X500Name subject = x500NameBld.build();
PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(subject, kp.getPublic());
PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(
kp.getPrivate()));
JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider("SC");
//serialization
ByteArrayOutputStream abOut = new ByteArrayOutputStream();
ASN1OutputStream berOut = new ASN1OutputStream(abOut);
berOut.writeObject(req2.toASN1Structure());
byte[] serializedData = abOut.toByteArray();
ASN1Primitive asn1Primitive = ASN1Primitive.fromByteArray(serializedData);
System.out.println("");
System.out.println("" + asn1Primitive.toString());
And the output is
[[0, [[[2.5.4.6, AU]], [[2.5.4.10, The Legion of the Bouncy Castle]], [[2.5.4.7, Melbourne]], [[2.5.4.8, Victoria]], [[1.2.840.113549.1.9.1, feedback-crypto#bouncycastle.org]]], [[1.2.840.113549.1.1.1, NULL], #03818D0030818902818100A...
I don't want to parse this manually. What should I do instead?
Forget about ASN1, it is a mess, and there seems to be no automatic deserialization. However, you can use the JcaPEMWriter and PEMParser classes in BouncyCastle to create a String object to serialize or deserialize the data, and send it over the network.
StringWriter sw = new StringWriter();
JcaPEMWriter pemWriter = new JcaPEMWriter(sw);
pemWriter.writeObject(req2);
pemWriter.close();
PEMParser pemParser = null;
try
{
pemParser = new PEMParser(new StringReader(sw.toString()));
Object parsedObj = pemParser.readObject();
System.out.println("PemParser returned: " + parsedObj);
if (parsedObj instanceof PKCS10CertificationRequest)
{
JcaPKCS10CertificationRequest jcaPKCS10CertificationRequest = new JcaPKCS10CertificationRequest((PKCS10CertificationRequest)parsedObj);
System.out.println("" + jcaPKCS10CertificationRequest.getPublicKey());
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
finally
{
if (pemParser != null)
{
pemParser.close();
}
}
EDIT: Although if someone really needs to get elements out of ASN1Encodable object (like an RDN of X500Name, apparently you need the IETFUtils class as per https://stackoverflow.com/a/5527171/2413303 .

Generate passbook signature in Java

I haven't seen any examples on the internet for this so as far as I know this is the first time someone is trying this in Java which I find hard to believe.
I'm just trying to work with the .pem, .p12 and .cer files I've been given to generate a signature file for my manifest.json. Here is what I have, which gives me an InvalidKeyException version mismatch: (supported: 00, parsed: 03
See the comment in the code below where the error is happening. I've viewed a few examples in another languages of how people are doing this with openssl but there must be a Java equivalent??
File pemFile = new File("AWWdevCert.pem");
File passCer = new File("pass.cer");
File passP12 = new File("pass.p12");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(FileUtils.readFileToByteArray(passP12));
PrivateKey privKey = keyFactory.generatePrivate(ks); // ERROR HERE
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(FileUtils.readFileToByteArray(passCer));
X509Certificate passCert = (X509Certificate)certFactory.generateCertificate(in); //don't know what to do with this
File inputFile = new File("WebContent/WEB-INF/Lowes.raw/manifest.json");
FileInputStream freader = null;
int sizecontent = ((int) inputFile.length());
byte[] contentbytes = new byte[sizecontent];
freader = new FileInputStream(inputFile);
System.out.println("\nContent Bytes: " + freader.read(contentbytes, 0, sizecontent));
freader.close();
Signature signature = Signature.getInstance("Sha1WithRSA");
signature.initSign(privKey);
signature.update(contentbytes);
byte[] signedData = signature.sign();
//create signature file
File signatureFile = new File(passDirectory.getAbsolutePath()+File.separator+"signature");
Check this jpasskit project on github
You can also generate signature by using only native sun.security package. Here is an example in Scala (can be easily rewritten for Java)
import java.security.cert.X509Certificate
import java.security.{MessageDigest, PrivateKey, Signature}
import java.util.Date
import sun.security.pkcs._
import sun.security.util.DerOutputStream
import sun.security.x509.{AlgorithmId, X500Name}
object PKPassSigner {
def sign(
signingCert: X509Certificate,
privateKey: PrivateKey,
intermediateCert: X509Certificate,
dataToSing: Array[Byte]
): Array[Byte] = {
val digestAlgorithmId = new AlgorithmId(AlgorithmId.SHA_oid)
val md = MessageDigest.getInstance(digestAlgorithmId.getName)
val attributes = new PKCS9Attributes(Array(
new PKCS9Attribute(PKCS9Attribute.SIGNING_TIME_OID, new Date()),
new PKCS9Attribute(PKCS9Attribute.MESSAGE_DIGEST_OID, md.digest(dataToSign)),
new PKCS9Attribute(PKCS9Attribute.CONTENT_TYPE_OID, ContentInfo.DATA_OID)
))
val signature = Signature.getInstance("Sha1WithRSA")
signature.initSign(privateKey)
signature.update(attributes.getDerEncoding)
val signedData = signature.sign()
val signerInfo = new SignerInfo(
X500Name.asX500Name(signingCert.getIssuerX500Principal),
signingCert.getSerialNumber,
digestAlgorithmId,
attributes,
AlgorithmId.get(privateKey.getAlgorithm),
signedData,
null
)
val p7 = new PKCS7(
Array(digestAlgorithmId),
new ContentInfo(ContentInfo.DATA_OID, null),
Array(signingCert, intermediateCert),
Array(signerInfo)
)
val out = new DerOutputStream()
p7.encodeSignedData(out)
out.flush()
val res = out.toByteArray
out.close()
res
}
}

Digital Signature in SOAP message

I'm trying to create a SOAP message with signature (Russian GOST34.10-2001 algorithm) in Java for some goverment services. The thing is that the service tells me that Signature is invalid and I can't see where I made a mistake. The key container where I read private key and certificate from is valid.
Where things go wrong? I understand that my question is quite specific but I still hope that someone could show me the way.
update1:a little update: body of message has some cyrillic(utf)-8 nodes and values
update2:
So I read through this question and tried to get the PrivateKey in the same way and got this Exception:
java.lang.IllegalArgumentException: private key algorithm does not match algorithm of public key in end entity certificate
Here's some code:
Here I marshal classes into SOAP body:
try {
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage sm = mf.createMessage();
SOAPPart sp = sm.getSOAPPart();
SOAPEnvelope envelope = sp.getEnvelope();
QName bodyId = new QName("http://ws.unisoft/", "SendFullULRequest");
SOAPBody sb = (SOAPBody) envelope.getBody();
SOAPHeader sh = (SOAPHeader) envelope.getHeader();
javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(FullULRq.class);
javax.xml.bind.Marshaller marshaller = jaxbCtx.createMarshaller();
marshaller.marshal(new JAXBElement<FullULRq>(bodyId, FullULRq.class, fulr),
sm.getSOAPBody());
sm.saveChanges();
Then I compute Digest Value:
ReferenceType rt2 = new ReferenceType();
rt2.setURI("#body");
////Пункт 7
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source xmlSource = new DOMSource(sm.getSOAPBody());
Result outputTarget = new StreamResult(outputStream);
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.transform(xmlSource, outputTarget);
Init.init();
Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
final ByteArrayInputStream is = new ByteArrayInputStream(canon.canonicalize(outputStream.toByteArray()));
rt2.setDigestValue(computeDigestWithStream(is));
} catch (Exception e) {
e.printStackTrace();
}
With this method:
public static byte[] computeDigestWithStream(ByteArrayInputStream stream) throws Exception {
final MessageDigest digest =
MessageDigest.getInstance("GOST3411");
// processing data
final DigestInputStream digestStream =
new DigestInputStream(stream, digest);
while (digestStream.available() != 0) {
digestStream.read();
}
And finally I generate a signature from the block (in which element is present):
ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
Source xmlSource2 = new DOMSource(sm.getSOAPBody());
Result outputTarget2 = new StreamResult(outputStream2);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.transform(xmlSource2, outputTarget2);
Init.init();
Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
InputStream is2 = new ByteArrayInputStream(outputStream2.toByteArray());
byte[] bb = canon.canonicalize(outputStream2.toByteArray());
byte[] signval = sign("CryptoProSignature", key, bb);
sign() method:
public static byte[] sign(String algorithmName, PrivateKey privateKey, byte[] data) throws Exception {
final Signature sig = Signature.getInstance(algorithmName);
sig.initSign(privateKey);
sig.update(data);
return sig.sign();
}
And if it is relevant this is how I read the privateKey from a container:
KeyStore ks = KeyStore.getInstance("FloppyStore");
String passwd = "*";
String kalias = null;
ks.load(null, null);
Enumeration enum1 = ks.aliases();
for (; enum1.hasMoreElements();) {
String tAlias = (String) enum1.nextElement();
if (ks.isKeyEntry(tAlias)) {
kalias = tAlias;
}
System.out.println(tAlias);
}
PrivateKey key = (PrivateKey) ks.getKey(kalias, passwd.toCharArray());
Thanks!

Categories