How to sign using ECDSA in Javacard - signing

I'm trying to implement the signing code using ECDSA.
But I always get a Error SW (6F00) during install phase.
I tried by changing parameters several times. (ex. ALG_EC_FP / ALG_EC_F2M, LENGTH_EC_FP_xxx / LENGTH_EC_F2M_xxx)
Could you tell me my mistake in my code below.
(Ver - JCDK 2.2.1, JDK 1.4.2)
package Test;
import javacard.framework.*;
import javacard.security.*;
import javacardx.crypto.*;
public class Test extends Applet{
private byte[] PLAINTEXT ;
private ECPrivateKey objECDSAPriKey=null; // Object for ECDSA Private Key
private ECPublicKey objECDSAPubKey=null; // Object for ECDSA Public Key
private KeyPair objECDSAKeyPair=null; // Object for ECDSA Key Pair
private Signature objECDSASign=null; // Object for ECDSA Signature
final static short BAS = 0;
//------------------------------------------------------------------------
public static void install(byte[] bArray, short bOffset, byte bLength){
new Test(bArray, bOffset, bLength);
}
private Test(byte bArray[], short bOffset, byte bLength){
PLAINTEXT = new byte[0x100] ; // Data file
Util.arrayFillNonAtomic(PLAINTEXT, BAS, (short)0x100, (byte)0);
// Error position (6F00)
objECDSAKeyPair= new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_192); // Error position (6F00)
// Create Signature Object
objECDSASign = Signature.getInstance(Signature.ALG_ECDSA_SHA, false);
register();
}
//------------------------------------------------------------------------
public void process(APDU apdu){
byte buf[] = apdu.getBuffer();
switch(buf[1])
{
case (byte)0xA4: break;
case (byte)0x46:
objECDSAKeyPair.genKeyPair();
objECDSAPriKey = (ECPrivateKey)objECDSAKeyPair.getPrivate();
objECDSAPubKey = (ECPublicKey)objECDSAKeyPair.getPublic();
break;
case (byte)0x2E:
short Le = apdu.setOutgoing();
short sSignLen=0 ;
// Init with Private Key
objECDSASign.init(objECDSAPriKey, Signature.MODE_SIGN);
//objECDSASign.init(objECDSAKeyPair.getPrivate(), Signature.MODE_SIGN);
// Sign Data
sSignLen = objECDSASign.sign(PLAINTEXT, BAS, Le, buf, BAS);
apdu.setOutgoingLength(sSignLen);
apdu.sendBytes(BAS, sSignLen);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
return;
} }
I got a JCOP card and its specification, and I read that the card support ECC in the spec.
But I doubt that the spec is the card's spec and the card really support ECC.
Is there any way to check that???
Thank you in advance.

Please modify your code to
try
{
// Error position (6F00)
objECDSAKeyPair= new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_192);
}
catch(CryptoException c)
{
//this line will give you the reason of problem ![see image][1]
byte reason = c.getReason();
}
*image link : http://i.stack.imgur.com/dFXVd.png

Related

itextsharp signing pdf with signed hash

I'm trying to sign a pdf through a signing service. This service requires to send a hex encoded SHA256 digest and in return I receive a hex encoded signatureValue. Besides that I also receive a signing certificate, intermediate certificate, OCSP response, and TimeStampToken. However, I already get stuck trying to sign the pdf with the signatureValue.
I have read Bruno's white paper, browsed the internet excessively, and tried many different ways, but the signature keeps coming up as invalid.
My latest attempt:
First, prepare pdf
PdfReader reader = new PdfReader(src);
FileStream os = new FileStream(dest, FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Certificate = signingCertificate;
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, 8192);
string hashAlgorithm = "SHA-256";
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
PdfSignatureAppearance appearance2 = stamper.SignatureAppearance;
Stream stream = appearance2.GetRangeStream();
byte[] hash = DigestAlgorithms.Digest(stream, hashAlgorithm);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
Hash byte[] sh and convert to string as follows
private static String sha256_hash(Byte[] value)
{
using (SHA256 hash = SHA256.Create())
{
return String.Concat(hash.ComputeHash(value).Select(item => item.ToString("x2"))).ToUpper();
}
}
and send to signing service. The received hex encoded signatureValue I then convert to bytes
private static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length).Where(x => x % 2 == 0).Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();
}
Finally, create signature
private void CreateSignature(string src, string dest, byte[] sig)
{
PdfReader reader = new PdfReader(src); // src is now prepared pdf
FileStream os = new FileStream(dest, FileMode.Create);
IExternalSignatureContainer external = new MyExternalSignatureContainer(sig);
MakeSignature.SignDeferred(reader, "Signature1", os, external);
reader.Close();
os.Close();
}
private class MyExternalSignatureContainer : IExternalSignatureContainer
{
protected byte[] sig;
public MyExternalSignatureContainer(byte[] sig)
{
this.sig = sig;
}
public byte[] Sign(Stream s)
{
return sig;
}
public void ModifySigningDictionary(PdfDictionary signDic) { }
}
What am I doing wrong? Help is very much appreciated. Thanks!
Edit: Current state
Thanks to help from mkl and following Bruno's deferred signing example I've gotten past the invalid signature message. Apparently I don't receive a full chain from the signing service, but just an intermediate certificate, which caused the invalid message. Unfortunately, the signature still has flaws.
I build the chain like this:
List<X509Certificate> certificateChain = new List<X509Certificate>
{
signingCertificate,
intermediateCertificate
};
In the sign method of MyExternalSignatureContainer I now construct and return the signature container:
public byte[] Sign(Stream s)
{
string hashAlgorithm = "SHA-256";
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
byte[] ocspResponse = Convert.FromBase64String("Base64 encoded DER representation of the OCSP response received from signing service");
byte[] hash = DigestAlgorithms.Digest(s, hashAlgorithm);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, ocspResponse, null, CryptoStandard.CMS);
string messageDigest = Sha256_hash(sh);
// messageDigest sent to signing service
byte[] signatureAsByte = StringToByteArray("Hex encoded SignatureValue received from signing service");
sgn.SetExternalDigest(signatureAsByte, null, "RSA");
ITSAClient tsaClient = new MyITSAClient();
return sgn.GetEncodedPKCS7(hash, tsaClient, ocspResponse, null, CryptoStandard.CMS);
}
public class MyITSAClient : ITSAClient
{
public int GetTokenSizeEstimate()
{
return 0;
}
public IDigest GetMessageDigest()
{
return new Sha256Digest();
}
public byte[] GetTimeStampToken(byte[] imprint)
{
string hashedImprint = HexEncode(imprint);
// Hex encoded Imprint sent to signing service
return Convert.FromBase64String("Base64 encoded DER representation of TimeStampToken received from signing service");
}
}
Still get these messages:
"The signer's identity is unknown because it has not been included in the list of trusted identities and none or its parent
certificates are trusted identities"
"The signature is timestamped, but the timestamp could not be verified"
Further help is very much appreciated again!
"What am I doing wrong?"
The problem is that on one hand you start constructing a CMS signature container using a PdfPKCS7 instance
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
and for the calculated document digest hash retrieve the signed attributes to be
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
to send them for signing.
So far so good.
But then you ignore the CMS container you started constructing but instead inject the naked signature bytes you got from your service into the PDF.
This cannot work as your signature bytes don't sign the document directly but instead they sign these signed attributes (and, therefore, indirectly the document as the document hash is one of the signed attributes). Thus, by ignoring the CMS container under construction you dropped the actually signed data...
Furthermore, the subfilter ADBE_PKCS7_DETACHED you use promises that the embedded signature is a full CMS signature container, not a few naked signature bytes, so the format also is wrong.
How to do it instead?
Instead of injecting the naked signature bytes you got from your service into the PDF as is, you have to set them as external digest in the PdfPKCS7 instance in which you originally started constructing the signature container:
sgn.SetExternalDigest(sig, null, ENCRYPTION_ALGO);
(ENCRYPTION_ALGO must be the encryption part of the signature algorithm, I assume in your case "RSA".)
and then you can retrieve the generated CMS signature container:
byte[] encodedSig = sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
Now this is the signature container to inject into the document using MyExternalSignatureContainer:
IExternalSignatureContainer external = new MyExternalSignatureContainer(encodedSig);
MakeSignature.SignDeferred(reader, "Signature1", os, external);
Remaining issues
Having corrected your code Adobe Reader still warns about your signatures:
"The signer's identity is unknown because it has not been included in the list of trusted identities and none or its parent certificates are trusted identities"
This warning is to be expected and correct!
The signer's identity is unknown because your signature service uses merely a demo certificate, not a certificate for production use:
As you see the certificate is issued by "GlobalSign Non-Public HVCA Demo", and non-public demo issuers for obvious reasons must not be trusted (unless you manually add them to your trust store for testing purposes).
"The signature is timestamped, but the timestamp could not be verified"
There are two reasons why Adobe does not approve of your timestamp:
On one hand, just like above, the timestamp certificate is a non-public, demo certificate ("DSS Non-Public Demo TSA Responder"). Thus, there is no reason for the verifier to trust your timestamp.
On the other hand, though, there is an actual error in your timestamp'ing code, you apply the hashing algorithm twice! In your MyITSAClient class you have
public byte[] GetTimeStampToken(byte[] imprint)
{
string hashedImprint = Sha256_hash(imprint);
// hashedImprint sent to signing service
return Convert.FromBase64String("Base64 encoded DER representation of TimeStampToken received from signing service");
}
The imprint parameter of your GetTimeStampToken implementation is already hashed, so you have to hex encode these bytes and send them for timestamp'ing. But you apply your method Sha256_hash which first hashes and then hex encodes this new hash.
Thus, instead of applying Sha256_hash merely hex encode the imprint!

Read the SMS activation code automatically in Xamarin Forms instead of manually typing it by user

I wrote a project with Xamarin Forms. When every user has signed up, I send him/her an activation Code to confirm it and the user has to insert it to enter the app. But I am looking for a plugin or a way that the user does not need to insert the activation Code.
I want the activation Code to be read automatically without the need to enter it manually.
First add the required permissions in AndroidManifest:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
Here is SmsReceiver class in Android project:
using System.Linq;
using System.Text.RegularExpressions;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Telephony;
using Java.Lang;
using Xamarin.Forms;
namespace MyProject.Android
{
[BroadcastReceiver(Enabled = true, Label = "SMS Receiver")]
[IntentFilter(new string[] { "android.provider.Telephony.SMS_RECEIVED", Intent.CategoryDefault })]
public class SmsReceiver : BroadcastReceiver
{
private const string IntentAction = "android.provider.Telephony.SMS_RECEIVED";
private static readonly string Sender = "SMS Sender number here";
private static readonly string[] OtpMessageBodyKeywordSet = {"Keyword1", "Keyword2"}; //You must define your own Keywords
public override void OnReceive(Context context, Intent intent)
{
try
{
if (intent.Action != IntentAction) return;
var bundle = intent.Extras;
if (bundle == null) return;
var pdus = bundle.Get("pdus");
// var castedPdus = JNIEnv.GetArray(pdus.Handle);
var castedPdus = JNIEnv.GetArray<Object>(pdus.Handle);
var msgs = new SmsMessage[castedPdus.Length];
var sb = new StringBuilder();
string sender = null;
for (var i = 0; i < msgs.Length; i++)
{
var bytes = new byte[JNIEnv.GetArrayLength(castedPdus[i].Handle)];
JNIEnv.CopyArray(castedPdus[i].Handle, bytes);
string format = bundle.GetString("format");
msgs[i] = SmsMessage.CreateFromPdu(bytes, format);
if (sender == null)
sender = msgs[i].OriginatingAddress;
sb.Append(string.Format("SMS From: {0}{1}Body: {2}{1}", msgs[i].OriginatingAddress,
System.Environment.NewLine, msgs[i].MessageBody));
//Toast.MakeText(context, sb.ToString(), ToastLength.Long).Show();
//Log.Error("Vahid", sb.ToString());
var msgBody = msgs[i].MessageBody;
if(!sender.Contains(Sender)) return;
bool foundKeyword = OtpMessageBodyKeywordSet.Any(k => msgBody.Contains(k));
if (!foundKeyword) return;
var code = ExtractNumber(msgBody);
MessagingCenter.Send<RegisterSecondPageModel, string>(new RegisterSecondPageModel(), "OtpReceived", code);
}
}
catch (System.Exception ex)
{
//Toast.MakeText(context, ex.Message, ToastLength.Long).Show();
}
}
private static string ExtractNumber(string text)
{
if (string.IsNullOrEmpty(text)) return "";
var regPattern = #"\d+";
var number = Regex.Match(text, regPattern).Value;
return number;
}
}
}
Note: In order to filter out the coming SMSes and detect only our own SMS we can apply these two filters:
1- Ignoring all SMSes that their sender numbers are not our SMS sender number.
2- Sometimes our SMS sender might send different SMSes to our clients, for example one SMS to send an activation code, and another to inform and confirm user's successfully registration in system. That said, we gotta distinguish them. For that we can search message body in order to find some pre-defined keywords. Of course our SMS server has to stick to a defined body format. "Activation", "Code", "Activation code" could be some example keywords in English language. Of course keywords should be defined in each language accordingly.
Here is RegisterSecondPageModel inside PCL project:
public class RegisterSecondPageModel
{
public RegisterSecondPageModel()
{
SubscribeToOtpReceiving();
}
private void SubscribeToOtpReceiving()
{
MessagingCenter.Subscribe<RegisterSecondPageModel, string>(this, "OtpReceived", (sender, code) =>
{
ActivationCode = code;
});
}
}
Another note is that as Jason already said, iOS doesn't allow apps to read SMSes.
If you're already sure about your clients having a SIM card in their device, then you can create a token and authenticate backwards, sending an SMS containing your token to from clients' device to your number.
Pros:
No blocked numbers: Sending messages from client is not blocked even if you're on their blacklist or they're blocking advertisements and unknown senders.
No costs on your side for authentication.
This works also in iOS which you can't read but can send messages.
Cons:
Client may be using another number in another device. This can be overcome by creating easy-to-type tokens which expire fast enough not to attract brute force attacks.
Client may not be able to send an SMS to your number due to several reasons including but not limited to not having enough account charge.

In Itext 7, how to sign a pdf with 2 steps?

Following the answers given in this previous question : In Itext 7, how to get the range stream to sign a pdf?, i've tried to reimplement the two steps signing method working in Itext 5 but i encounter an issue when trying to reopen the document result of the first step (with the PdfReader or a pdf reader).(invalid document)
Here is the presigning part for a document already containing an empty signature field named certification ... why is the result of this step invalid ?
PdfReader reader = new PdfReader(fis);
Path signfile = Files.createTempFile("sign", ".pdf");
FileOutputStream os = new FileOutputStream(signfile.toFile());
PdfSigner signer = new PdfSigner(reader, os, false);
signer.setFieldName("certification"); // this field already exists
signer.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING);
PdfSignatureAppearance sap = signer.getSignatureAppearance();
sap.setReason("Certification of the document");
sap.setLocation("On server");
sap.setCertificate(maincertificate);
BouncyCastleDigest digest = new BouncyCastleDigest();
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, digest,false);
//IExternalSignatureContainer like BlankContainer
PreSignatureContainer external = new PreSignatureContainer(PdfName.Adobe_PPKLite,PdfName.Adbe_pkcs7_detached);
signer.signExternalContainer(external, 8192);
byte[] hash=external.getHash();
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null,PdfSigner.CryptoStandard.CMS);// sh will be sent for signature
And here is the PreSignatureContainer class :
public class PreSignatureContainer implements IExternalSignatureContainer {
private PdfDictionary sigDic;
private byte hash[];
public PreSignatureContainer(PdfName filter, PdfName subFilter) {
sigDic = new PdfDictionary();
sigDic.put(PdfName.Filter, filter);
sigDic.put(PdfName.SubFilter, subFilter);
}
#Override
public byte[] sign(InputStream data) throws GeneralSecurityException {
String hashAlgorithm = "SHA256";
BouncyCastleDigest digest = new BouncyCastleDigest();
try {
this.hash= DigestAlgorithms.digest(data, digest.getMessageDigest(hashAlgorithm));
} catch (IOException e) {
throw new GeneralSecurityException("PreSignatureContainer signing exception",e);
}
return new byte[0];
}
#Override
public void modifySigningDictionary(PdfDictionary signDic) {
signDic.putAll(sigDic);
}
public byte[] getHash() {
return hash;
}
public void setHash(byte hash[]) {
this.hash = hash;
}
}
why is the result of this step invalid
Because you essentially discovered a bug... ;)
Your sample input file has one feature which triggers the bug: It is compressed using object streams.
When iText manipulates such a file, it also tries to put as many objects as possible into object streams. Unfortunately it also does so with the signature dictionary. This is unfortunate because after writing the whole file it tries to enter some information (which are not available before) into this dictionary which damages the compressed object stream.
What you can do...
You can either
wait for iText development to fix this issue - I assume this won't take too long but probably you don't have the time to wait; or
convert the file to sign into a form which does not use object streams - this can be done using iText itself but probably you cannot accept the file growth this means, or probably the files already are signed which forbids any such transformation; or
patch iText 7 to force the signature dictionary not to be added to an object stream - it is a trivial patch but you probably don't want to used patched libraries.
The patch mentioned above indeed is trivial, the method PdfSigner.preClose(Map<PdfName, Integer>) contains this code:
if (certificationLevel > 0) {
// add DocMDP entry to root
PdfDictionary docmdp = new PdfDictionary();
docmdp.put(PdfName.DocMDP, cryptoDictionary.getPdfObject());
document.getCatalog().put(PdfName.Perms, docmdp); // TODO: setModified?
}
document.close();
The cryptoDictionary.getPdfObject()) is the signature dictionary I mentioned above. During document.close() it is added to an object stream unless it has been written to the output before. Thus, you simply have to add a call to flush that object right before that close call and by parameter make clear that it shall not be added to an object stream:
cryptoDictionary.getPdfObject().flush(false);
With that patch in place, the PDFs your code returns are not damaged as above anymore.
As an aside, iText 5 does contain a similar line in the corresponding PdfSignatureAppearance.preClose(HashMap<PdfName, Integer>) right above the if block corresponding to the if block above. It seems to have been lost during refactoring to iText 7.

WebRTC unable to decode text message sent from Datachannel

I am trying to use WebRTC datachannel for the first time. I can sent text using WebRTC javascript code, and can catch the event from my WebRTC android code.
I am following procedure :
From JavaScript client :
function sendMsg(msg){
if(dataChannel.readyState=="open"){
dataChannel.send(msg); //dataChannel = my datachannel object
}
else{
console.error("data channel no ready");
}
}
From WebRTC android client:
public void onMessage(final Buffer arg0) {
byte[] bytearr = new byte[arg0.data.remaining()];
//Case 1:
Log.e("MSG_GOT",arg0.data.get(bytearr).toString());
//Case 2:
Log.e("MSG_GOT " + arg0.data.toString());
}
For case 1 :
I am getting some unreadable data, which I assume is encoded.
For case 2:
I am getting an object as java.nio.ReadWriteDirectByteBuffer, status: capacity=6 position=6 limit=6 .
I was sending abcdef as text.
How can I decode this into readable text ? Or is there any function provided by WebRTC android api to decode it ?
I am using the following function, that works when I send String payloads.
public void onMessage(DataChannel.Buffer buffer) {
ByteBuffer data = buffer.data;
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
final String message = new String(bytes);
// ...
}
I remember it is from a similar question/answer which I cannot find right now.

Windows 8 Metro RSA Encryption: AsymmetricKeyAlgorithmProvider ImportPublicKey Fails

I am attempting to pass some encrypted data between a Win 8 Metro app and a RESTful WCF service. Initially the Metro app requests a public key and the WCF service returns it as a raw Stream as to avoid any pesky formatting issues. The Base 64 encoded public key is decoded in the metro app into a byte array. Here is where the problem occurs. When I attempted to call AsymmetricKeyAlgorithmProvider.ImportPublicKey I get the error "ASN1 bad tag value met".
I am using RSA PKCS1 for the encryption. Here is the relevant code:
WCF Service
string keyName = "This is passed in via a parameter";
var key = !CngKey.Exists(keyName) ? CngKey.Create(CngAlgorithm2.Rsa, keyName) : CngKey.Open(keyName);
// Create the RSA container to get keys and then dispose
using (var rsaCng = new RSACng(key) { EncryptionPaddingMode = AsymmetricPaddingMode.Pkcs1, KeySize = 2048 })
{
byte[] publicBlob = rsaCng.Key.Export(CngKeyBlobFormat.GenericPublicBlob);
publicKey = Convert.ToBase64String(publicBlob);
}
Metro App
public static string Encrypt(IBuffer dataBuffer, string publicKeyString)
{
var asymmAlg = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
// The next line fails with ASN1 bad tag value met
var publicKey = asymmAlg.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(publicKeyString), CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
var encryptedData = CryptographicEngine.Encrypt(publicKey, dataBuffer, null);
return CryptographicBuffer.EncodeToBase64String(encryptedData);
}
EDIT 1: More information below
Exporting the public key from a 2048bit key pair from the WCF service yields a 283 bit length key blob, while exporting the same type of public key from the Metro app is only 270 bits. When I import the Metro generated public key it succeeds. Any idea why the WCF service has 13 extra bits on its public key? I think those extra 13 bits are causing the failure.
Here is the Metro code that yields the shorter public key blob:
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey standardKeyPair = provider.CreateKeyPair(2048);
byte[] standardKey = standardKeyPair.ExportPublicKey(CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey).ToArray();
Quite late, but maybe it will help you or saves someone's time...
Change the type of blob type during import. It's really wierd, but I had success with it, after experimenting.
Your code in WCF may stay as it is.
Change just the Metro code:
public static string Encrypt(IBuffer dataBuffer, string publicKeyString)
{
var asymmAlg = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
// The next line fails with ASN1 bad tag value met
var publicKey = asymmAlg.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(publicKeyString), CryptographicPublicKeyBlobType.BCryptPublicKey);
var encryptedData = CryptographicEngine.Encrypt(publicKey, dataBuffer, null);
return CryptographicBuffer.EncodeToBase64String(encryptedData);
}
So the only change here is the BCryptPublicKey during the importing. Then it works. But do not ask me why :-).