I have a signedCMS, and would like to know how to use Bouncy Castle API to remove the signature so I can have clear access to the plain text file underneath?
Thanks
Something like this might work:
CMSSignedData signedData = new CMSSignedData(signedFileBytes);
// Now get the content contained in the CMS EncapsulatedContentInfo
CMSProcessable processable = signedData.getSignedContent();
You should then be able to get a stream on processable from which the data can be read.
Related
Right, so I am completely stumped. Usually when I sign certificates I use an ASN.1 like below to specify specific rules, that can be used for IoT for example.
1.2.3.4=ASN1:SEQUENCE:seq_sect
[seq_sect]
one=SEQUENCE:do_one
two=SEQUENCE:do_two
[do_one]
field.1 = UTF8:field1/*
field.2 = UTF8:field2/*
[do_two]
field.1 = UTF8:field1/*
field.2 = UTF8:field2/*
I usually use a program called xca, but in this case I have been coding with bouncycastle and have been really struggling in importing this into the X509v3CertificateBuilder. I know I should be using .addExtension, but I'm not particularly certain if I should store the rules in a .txt file or if I should store it in an array and somehow parse through it?
Actually you're using OpenSSL, which xca wraps. Only OpenSSL uses this particular text-based 'config' format for ASN.1. For BouncyCastle you'll have to write code instead, something like (not tested):
ASN1EncodableVector one = new ASN1EncodableVector();
one.add(new DERUTF8String("field1/*"));
one.add(new DERUTF8String("field2/*"));
// if two is really identical to one, just reuse it; otherwise do something different
ASN1EncodableVector outer = new ASN1EncodableVector();
outer.add(new DERSequence(one));
outer.add(new DERSequence(two)); // or one again
builder.addExtension (oid, critical, new DERSequence(outer));
Similar How to add PrivateKeyUsage extension to a certificate using bouncycastle in java? and Creating Custom X509 v3 Extensions in Java with Bouncy Castle
The plain text is signed using java.security.Signature. Below is the code used to sign the plain text
public String getSignature(String plainText) throws Exception
{
KeyStore keyStore = loadKeyStore(); // A local method to read the keystore file from file system.
PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray());
Signature privateSignature = Signature.getInstance(SIGNATUREALGO);
privateSignature.initSign(privateKey);
privateSignature.update(plainText.getBytes("UTF-8"));
byte[] signature = privateSignature.sign();
return String.valueOf(signature);
// KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD and SIGNATUREALGO are all constant Strings
}
Note 1: I found online a way to verify the signature using the public key Java Code Examples for java.security.Signature#verify(). But this is not what I require.
Note 2: I also found a ways to encrypt and decrypt as mentioned here RSA Signing and Encryption in Java. But the use case I have in hand is to get the original plain text from a signed data. Is that possible?
No, you can't retrieve the original content from just the signature.
The signature alone does not contain enough information to restore the original clear text, no matter what keys you have access to.
The basic idea of a signature is to send it together with the clear text. That means the clear text will be visible, but the signature can be used to verify that the message was written (or at least signed) by who claims to have done so and has not been tampered with since then.
Signing something is different from encrypting it. The two often uses the same or related technologies and both fall under cryptography.
using following code; when i tries to get access the signed from the PKCS7 attached signature.
cms = new CMSSignedData(envelopedData); //PKCS7 envelope
String signedData = new String((byte[])cms.getSignedContent().getContent());
I got the output like this.
nº™(5š?¶ÁNšc«n‘¶˜Êõûøˆ‚<ùæB0¸ð¿ø"˜ZÊ×`—õWøž8¹¨c¼‘Ç{¥é×Æx¢ôãÕ›|?€çžÆ3ÔÜç&¦¤X„õ·3c'Gž\³Ö/€Á<ž²¬ÿµƒÉâw…«b›¤?¤1®kB•ô?³Á2€¦?r`!¦÷nt¯*Ÿ
Same thing works fine for detached signature. For attached signature, i used the following code.
CMSSignedData sigData = gen.generate(msg, true);
Even. I tried all the charsets for the signedData String.
I found the problem and resolved it. It was due to the double signing process.
At the moment in C# I'm signing a challenge like this:
RSACryptoServiceProvider rsa;
RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(rsa);
RSAFormatter.SetHashAlgorithm("SHA1");
byte[] SignedHash = RSAFormatter.CreateSignature(paramDataToSign);
Then I give the SignedHash to Windows, it accepts it and everything is OK. But I need to move this part to Android and there's the problem, that I just can't get the same signed hash value.
In Android I tried to make the signed hash but they differ from the one generated in C#.
Signature signer = Signature.getInstance("SHA1withRSA", "BC");
signer.initSign(privateKey);
signer.update(paramDataToSign);
signer.sign();
In C# - using the following piece of code - I get the same result as in Android, but it is not an option cause then Windows does not accept the signed hash.
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
signer.Init(true, privateKey);
signer.BlockUpdate(paramDataToSign, 0, paramDataToSign.Length);
signer.GenerateSignature();
Here's written that C# PKCS1SignatureFormatter and Java Signature should give the same result, but they do not. http://www.jensign.com/JavaScience/dotnet/VerifySig/
What could be the problem?
Here are the base 64 (WebSafe) values that I get:
Challenge = zHyz12Tk4m151nssYIBWqBCAxhQ
RSAPKCS1SignatureFormatter SignedHash = kmu39keplCAV4Qnu22wdprLz4nGSsrVtHbxQ5YMUG7p-0YwReCG4ROIlFvYs4CGfjCiAGFPw4PLrLx7mrlAA6iuhJMkgm_PMTW9alQYTH612hLEUP4EmK0M2kw8CveLcjI3HA08z8bByllIzRyAlM8bcR438vw2uhx_CbgvOOHn8vwBPnvWbFqpi2doYoq2xEuFBRe7eBPrxbMRqEd3ExdQ9c9rYT4ivOJ4pbioyi6D5i5_1crvGwM6nQanMZCmooRYJO65NP3B4wWnvQZpJLRD0U08wWcvyGBFWp188ZovDjnkTQZku6lzmwGXfqQwtBz9uNvLcTbp7cVyt5EyQxw
Signature and ISigner SignedHash = Vt-b5QfGPnSPpZuIB8-H4N1K5hQXpImS4e8k56_HruDSqy3DLsz96QKUrccshjr1z9nTK3Mwvd5yPdyTJOqSUcDQqxV46LPhWQNsubqKxAz97ePpeslIH1gHdnzkh46ixsWqgDrhR7egQtDkU8PPsph1qahCxaVkRYspQBV0jPZ-LK4EjoGGnuWTCihVKjruXJZ2VY8yZ9QRAsHVptr0Nv-mldO2MFK-oEVbtVbHqUPf5So8im3oRSm68OqY4g56bCdFNSbhcFBjrZ1QPjnxiIk43-_5tevafqoOB2D_E_mQHCJwmRg3MrNij6IdAdloCejnhCWzgMHdcG1Ug_Qmig
EDIT:
So the simplest solution is using Bouncy Castle API:
AsymmetricBlockCipher rsaEngine = new PKCS1Encoding(new RSABlindedEngine());
rsaEngine.init(true, privateKey);
DigestInfo dInfo = new DigestInfo(new AlgorithmIdentifier(X509ObjectIdentifiers.id_SHA1, DERNull.INSTANCE), paramDataToSign);
byte[] digestInfo = dInfo.getEncoded(ASN1Encoding.DER);
rsaEngine.processBlock(digestInfo, 0, digestInfo.length);
The problem is that RSAFormatter.CreateSignature(paramDataToSign); passes the hash value, while signer.update(paramDataToSign); passes the data before it is hashed. So it is likely that you have to remove a MessageDigest calculation for your Java code for this to work.
Alternatively, if you only have the hash value, you may have a look into the Bouncy Castle lightweight API to find a method that accepts a value that is pre-hashed. This can probably be performed using new RSADigestSigner(new StaticDigest(paramDataToSign, "SHA-1")).generateSignature().
Problem is that StaticDigest does not exist, so you'll have to comment here if you really require it. Alternative, mirror the implementation of RSADigestSigner but substitute a pre-calculated hash.
I have a servlet and the content type of my request is of type : application-pkcs-7
And how do i decode the request ?
Any ideas ?
I learnt that i can use openssl to decode , but not much docs on that .
That's probably a signature or an encrypted piece of data. It's old name is PKCS-7 (of RSA labs, publicly available standard) but it is also known as CMS (Cryptographic Message Syntax, publicly available RFC). CMS is a container format for different kinds of encryption. You can parse it in Java using the open source Bouncy Castle libraries - "bcmail" in particular, but you probably need some kind of key if it is encrypted. If it is signed, you could simply parse the plain text data from it and ignore the signature, I guess, depends on the application really.
[UPDATE] Since 1.47 the necessary functionality is in the PKIX library of Bouncy Castle.
Should work in this way
CMSSignedData cmsSignedData = new CMSSignedData(byte[] signedData);
CMSProcessable cmsProcessable = cmsSignedData.getSignedContent();
In my case it didn't though, because of unknown tag entry while parsing data