I would like to understand the difference between generating RSA 2048 bit keys through IAIK PKCS11Wrapper, where I am using the example class named GenerateKeyPair.java, and IAIK PKCS11Provider which also uses IAIK PKCS11Wrapper and generate key pair through example class named KeyPairGeneratorDemo.java.
I am using the above libraries and classes with USB token ACS CryptoMate64.
When I use PKCS11Wrapper and load my pkcs11.dll everything works fine. Key pair is generated.
But when I am trying to do the same through IAIK PKCS11Provider class, it is throwing an exception when trying to generate key pair keyPair_ = keyPairGenerator.generateKeyPair();:
Exception in thread "main" iaik.pkcs.pkcs11.provider.IAIKPkcs11Exception: iaik.pkcs.pkcs11.wrapper.PKCS11Exception: CKR_ATTRIBUTE_VALUE_INVALID
at iaik.pkcs.pkcs11.provider.keypairgenerators.PKCS11KeyPairGenerator.generateKeyPair(Unknown Source)
at java.security.KeyPairGenerator$Delegate.generateKeyPair(KeyPairGenerator.java:650)
at KeyPairGenerationDemo.generateKeyPairSimple(KeyPairGenerationDemo.java:114)
at KeyPairGenerationDemo.main(KeyPairGenerationDemo.java:91)
What's the difference between these two approaches? And why is key pair generation through IAIK PKCS11Provider throwing CKR_ATTRIBUTE_VALUE_INVALID? I know what that constant mean in PKCS11 standard but I don't fully understand why it is thrown when IAIK PKCS11Wrapper was successfull with that...
I am also attaching two classes that I'm using.
GenerateKeyPair.java
// Copyright (c) 2002 Graz University of Technology. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. The end-user documentation included with the redistribution, if any, must
// include the following acknowledgment:
//
// "This product includes software developed by IAIK of Graz University of
// Technology."
//
// Alternately, this acknowledgment may appear in the software itself, if and
// wherever such third-party acknowledgments normally appear.
//
// 4. The names "Graz University of Technology" and "IAIK of Graz University of
// Technology" must not be used to endorse or promote products derived from this
// software without prior written permission.
//
// 5. Products derived from this software may not be called "IAIK PKCS Wrapper",
// nor may "IAIK" appear in their name, without prior written permission of
// Graz University of Technology.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import iaik.pkcs.pkcs11.Mechanism;
import iaik.pkcs.pkcs11.MechanismInfo;
import iaik.pkcs.pkcs11.Module;
import iaik.pkcs.pkcs11.Session;
import iaik.pkcs.pkcs11.Slot;
import iaik.pkcs.pkcs11.Token;
import iaik.pkcs.pkcs11.TokenException;
import iaik.pkcs.pkcs11.TokenInfo;
import iaik.pkcs.pkcs11.objects.KeyPair;
import iaik.pkcs.pkcs11.objects.Object;
import iaik.pkcs.pkcs11.objects.RSAPrivateKey;
import iaik.pkcs.pkcs11.objects.RSAPublicKey;
import iaik.pkcs.pkcs11.wrapper.Functions;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
/**
* This demo program generates a 2048 bit RSA key-pair on the token and writes
* the public key to a file.
*/
public class GenerateKeyPair {
static BufferedReader input_;
static PrintWriter output_;
static {
try {
//output_ = new PrintWriter(new FileWriter("SignAndVerify_output.txt"), true);
output_ = new PrintWriter(System.out, true);
input_ = new BufferedReader(new InputStreamReader(System.in));
} catch (Throwable thr) {
thr.printStackTrace();
output_ = new PrintWriter(System.out, true);
input_ = new BufferedReader(new InputStreamReader(System.in));
}
}
public static void main(String[] args)
throws IOException, TokenException, NoSuchAlgorithmException,
InvalidKeySpecException
{
if (args.length < 2) {
printUsage();
throw new IOException("Missing argument!");
}
Module pkcs11Module = Module.getInstance(args[0]);
pkcs11Module.initialize(null);
Slot[] slots = pkcs11Module.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
if (slots.length == 0) {
output_.println("No slot with present token found!");
throw new TokenException("No token found!");
}
Slot selectedSlot;
if (2 < args.length) selectedSlot = slots[Integer.parseInt(args[2])];
else selectedSlot = slots[0];
Token token = selectedSlot.getToken();
TokenInfo tokenInfo = token.getTokenInfo();
output_
.println("################################################################################");
output_.println("Information of Token:");
output_.println(tokenInfo);
output_
.println("################################################################################");
Session session;
if (3 < args.length) session = Util.openAuthorizedSession(token,
Token.SessionReadWriteBehavior.RW_SESSION, output_, input_, args[3]);
else session = Util.openAuthorizedSession(token,
Token.SessionReadWriteBehavior.RW_SESSION, output_, input_, null);
output_
.println("################################################################################");
output_.print("Generating new 2048 bit RSA key-pair... ");
output_.flush();
// first check out what attributes of the keys we may set
HashSet supportedMechanisms = new HashSet(Arrays.asList(token.getMechanismList()));
MechanismInfo signatureMechanismInfo;
if (supportedMechanisms.contains(Mechanism.get(PKCS11Constants.CKM_RSA_PKCS))) {
signatureMechanismInfo = token.getMechanismInfo(Mechanism
.get(PKCS11Constants.CKM_RSA_PKCS));
} else if (supportedMechanisms.contains(Mechanism.get(PKCS11Constants.CKM_RSA_X_509))) {
signatureMechanismInfo = token.getMechanismInfo(Mechanism
.get(PKCS11Constants.CKM_RSA_X_509));
} else if (supportedMechanisms.contains(Mechanism.get(PKCS11Constants.CKM_RSA_9796))) {
signatureMechanismInfo = token.getMechanismInfo(Mechanism
.get(PKCS11Constants.CKM_RSA_9796));
} else if (supportedMechanisms.contains(Mechanism
.get(PKCS11Constants.CKM_RSA_PKCS_OAEP))) {
signatureMechanismInfo = token.getMechanismInfo(Mechanism
.get(PKCS11Constants.CKM_RSA_PKCS_OAEP));
} else {
signatureMechanismInfo = null;
}
Mechanism keyPairGenerationMechanism = Mechanism
.get(PKCS11Constants.CKM_RSA_PKCS_KEY_PAIR_GEN);
RSAPublicKey rsaPublicKeyTemplate = new RSAPublicKey();
RSAPrivateKey rsaPrivateKeyTemplate = new RSAPrivateKey();
// set the general attributes for the public key
rsaPublicKeyTemplate.getModulusBits().setLongValue(new Long(2048));
byte[] publicExponentBytes = { 0x01, 0x00, 0x01 }; // 2^16 + 1
rsaPublicKeyTemplate.getPublicExponent().setByteArrayValue(publicExponentBytes);
rsaPublicKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
byte[] id = new byte[20];
new Random().nextBytes(id);
rsaPublicKeyTemplate.getId().setByteArrayValue(id);
//rsaPublicKeyTemplate.getLabel().setCharArrayValue(args[2].toCharArray());
rsaPrivateKeyTemplate.getSensitive().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getPrivate().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getId().setByteArrayValue(id);
//byte[] subject = args[1].getBytes();
//rsaPrivateKeyTemplate.getSubject().setByteArrayValue(subject);
//rsaPrivateKeyTemplate.getLabel().setCharArrayValue(args[2].toCharArray());
// set the attributes in a way netscape does, this should work with most tokens
if (signatureMechanismInfo != null) {
rsaPublicKeyTemplate.getVerify().setBooleanValue(
new Boolean(signatureMechanismInfo.isVerify()));
rsaPublicKeyTemplate.getVerifyRecover().setBooleanValue(
new Boolean(signatureMechanismInfo.isVerifyRecover()));
rsaPublicKeyTemplate.getEncrypt().setBooleanValue(
new Boolean(signatureMechanismInfo.isEncrypt()));
rsaPublicKeyTemplate.getDerive().setBooleanValue(
new Boolean(signatureMechanismInfo.isDerive()));
rsaPublicKeyTemplate.getWrap().setBooleanValue(
new Boolean(signatureMechanismInfo.isWrap()));
rsaPrivateKeyTemplate.getSign().setBooleanValue(
new Boolean(signatureMechanismInfo.isSign()));
rsaPrivateKeyTemplate.getSignRecover().setBooleanValue(
new Boolean(signatureMechanismInfo.isSignRecover()));
rsaPrivateKeyTemplate.getDecrypt().setBooleanValue(
new Boolean(signatureMechanismInfo.isDecrypt()));
rsaPrivateKeyTemplate.getDerive().setBooleanValue(
new Boolean(signatureMechanismInfo.isDerive()));
rsaPrivateKeyTemplate.getUnwrap().setBooleanValue(
new Boolean(signatureMechanismInfo.isUnwrap()));
} else {
// if we have no information we assume these attributes
rsaPrivateKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getDecrypt().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getVerify().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getEncrypt().setBooleanValue(Boolean.TRUE);
}
// netscape does not set these attribute, so we do no either
rsaPublicKeyTemplate.getKeyType().setPresent(false);
rsaPublicKeyTemplate.getObjectClass().setPresent(false);
rsaPrivateKeyTemplate.getKeyType().setPresent(false);
rsaPrivateKeyTemplate.getObjectClass().setPresent(false);
KeyPair generatedKeyPair = session.generateKeyPair(keyPairGenerationMechanism,
rsaPublicKeyTemplate, rsaPrivateKeyTemplate);
RSAPublicKey generatedRSAPublicKey = (RSAPublicKey) generatedKeyPair.getPublicKey();
RSAPrivateKey generatedRSAPrivateKey = (RSAPrivateKey) generatedKeyPair
.getPrivateKey();
// no we may work with the keys...
output_.println("Success");
output_.println("The public key is");
output_
.println("_______________________________________________________________________________");
output_.println(generatedRSAPublicKey);
output_
.println("_______________________________________________________________________________");
output_.println("The private key is");
output_
.println("_______________________________________________________________________________");
output_.println(generatedRSAPrivateKey);
output_
.println("_______________________________________________________________________________");
// write the public key to file
output_
.println("################################################################################");
output_.println("Writing the public key of the generated key-pair to file: "
+ args[1]);
RSAPublicKey exportableRsaPublicKey = generatedRSAPublicKey;
BigInteger modulus = new BigInteger(1, exportableRsaPublicKey.getModulus()
.getByteArrayValue());
BigInteger publicExponent = new BigInteger(1, exportableRsaPublicKey
.getPublicExponent().getByteArrayValue());
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
java.security.interfaces.RSAPublicKey javaRsaPublicKey = (java.security.interfaces.RSAPublicKey) keyFactory
.generatePublic(rsaPublicKeySpec);
X509EncodedKeySpec x509EncodedPublicKey = (X509EncodedKeySpec) keyFactory.getKeySpec(
javaRsaPublicKey, X509EncodedKeySpec.class);
FileOutputStream publicKeyFileStream = new FileOutputStream(args[1]);
publicKeyFileStream.write(x509EncodedPublicKey.getEncoded());
publicKeyFileStream.flush();
publicKeyFileStream.close();
output_
.println("################################################################################");
// now we try to search for the generated keys
output_
.println("################################################################################");
output_
.println("Trying to search for the public key of the generated key-pair by ID: "
+ Functions.toHexString(id));
// set the search template for the public key
RSAPublicKey exportRsaPublicKeyTemplate = new RSAPublicKey();
exportRsaPublicKeyTemplate.getId().setByteArrayValue(id);
session.findObjectsInit(exportRsaPublicKeyTemplate);
Object[] foundPublicKeys = session.findObjects(1);
session.findObjectsFinal();
if (foundPublicKeys.length != 1) {
output_.println("Error: Cannot find the public key under the given ID!");
} else {
output_.println("Found public key!");
output_
.println("_______________________________________________________________________________");
output_.println(foundPublicKeys[0]);
output_
.println("_______________________________________________________________________________");
}
output_
.println("################################################################################");
session.closeSession();
pkcs11Module.finalize(null);
}
public static void printUsage() {
output_
.println("Usage: GenerateKeyPair <PKCS#11 module> <X.509 encoded public key file> [<slot>] [<pin>]");
output_.println(" e.g.: GenerateKeyPair pk2priv.dll publicKey.xpk");
output_.println("The given DLL must be in the search path of the system.");
}
}
KeyPairGeneratorDemo.java
// Copyright (C) 2002 IAIK
// http://jce.iaik.at
//
// Copyright (C) 2003 - 2013 Stiftung Secure Information and
// Communication Technologies SIC
// http://www.sic.st
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
// class and interface imports
import iaik.pkcs.pkcs11.Mechanism;
import iaik.pkcs.pkcs11.TokenException;
import iaik.pkcs.pkcs11.Version;
import iaik.pkcs.pkcs11.objects.Attribute;
import iaik.pkcs.pkcs11.objects.BooleanAttribute;
import iaik.pkcs.pkcs11.objects.GenericTemplate;
import iaik.pkcs.pkcs11.objects.PrivateKey;
import iaik.pkcs.pkcs11.objects.PublicKey;
import iaik.pkcs.pkcs11.objects.RSAPublicKey;
import iaik.pkcs.pkcs11.provider.IAIKPkcs11;
import iaik.pkcs.pkcs11.provider.keypairgenerators.PKCS11KeyPairGenerationSpec;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import java.math.BigInteger;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.DSAParameterSpec;
import javax.crypto.spec.DHParameterSpec;
/**
* This class shows a short demonstration of how to use this provider
* implementation for a key-pair generation.
*/
public class KeyPairGenerationDemo {
/**
* The PKCS#11 JCE provider.
*/
protected IAIKPkcs11 pkcs11Provider_;
/**
* The new key-pair.
*/
protected KeyPair keyPair_;
/**
* This empty constructor registers the new provider to the Java
* security system.
*/
public KeyPairGenerationDemo() {
DemoUtils.addSoftwareProvider();
pkcs11Provider_ = new IAIKPkcs11();
Security.addProvider(pkcs11Provider_);
}
public static void main(String[] args)
throws GeneralSecurityException
{
KeyPairGenerationDemo demo = new KeyPairGenerationDemo();
String algorithm = (args.length > 0) ? args[0] : "RSA"; // specify the required asymmetric algorithm, e.g. DSA, ECDSA, ...
demo.generateKeyPairSimple(algorithm);
demo.generateKeyPairMultipleProvider(algorithm);
demo.generateKeyPairDetailed(algorithm);
demo.printKeyPair(algorithm);
System.out.flush();
System.err.flush();
}
/**
* This method generates a key-pair on a simple and not flexible way.
* On some tokens this method creates permanent keys although not needed
* or the other way round (the default settings of the token are used).
* It stores the key-pair in the member variable <code>keyPair_</code>.
*
* #exception GeneralSecurityException
* If anything with the provider fails.
*/
public void generateKeyPairSimple(String algorithm)
throws GeneralSecurityException
{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm,
pkcs11Provider_.getName());
keyPair_ = keyPairGenerator.generateKeyPair();
}
/**
* This method generates a key-pair for a specific instance of IAIK PKCS#11
* provider, if multiple instances are used in parallel.
* On some tokens this method creates permanent keys although not needed
* or the other way round (the default settings of the token are used).
* It stores the key-pair in the member variable <code>keyPair_</code>.
*
* #exception GeneralSecurityException
* If anything with the provider fails.
*/
public void generateKeyPairMultipleProvider(String algorithm)
throws GeneralSecurityException
{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm,
pkcs11Provider_.getName());
// get a default template
iaik.pkcs.pkcs11.objects.KeyPair template = IAIKPkcs11.getGlobalKeyHandler()
.getKeyPairGeneratorTemplate(algorithm, -1);
keyPairGenerator
.initialize((PKCS11KeyPairGenerationSpec) new PKCS11KeyPairGenerationSpec(
template.getPublicKey(), template.getPrivateKey()).setUseUserRole(true));
keyPair_ = keyPairGenerator.generateKeyPair();
}
/**
* This method generates a key-pair by specifying the required attributes.
* It stores the key-pair in the member variable <code>keyPair_</code>.
*
* #exception GeneralSecurityException
* If anything with the provider fails.
*/
public void generateKeyPairDetailed(String algorithm)
throws GeneralSecurityException
{
//get private key template with attributes sign, private and sensitive set to true and attribute token set to false
PrivateKey privateKeyTemplate = KeyTemplateDemo
.getSignaturePrivateKeyTemplate(algorithm);
//get public key template with attribute verify set to true and attribute token set to false
PublicKey publicKeyTemplate = KeyTemplateDemo
.getSignaturePublicKeyTemplate(algorithm);
//additionally a label can be set for the keys
privateKeyTemplate.getLabel().setCharArrayValue("demoPrivateKey".toCharArray());
publicKeyTemplate.getLabel().setCharArrayValue("demoPublicKey".toCharArray());
//since PKCS#11 standard version 2.20 you can use these attributes
//example for RSA
if (algorithm.equalsIgnoreCase("RSA")) {
try {
Version cryptokiVersion = IAIKPkcs11.getModule().getInfo().getCryptokiVersion();
if ((cryptokiVersion.getMajor() >= 2) && (cryptokiVersion.getMinor() >= 20)) {
GenericTemplate wrapTemplate = new GenericTemplate();
BooleanAttribute encrypt = new BooleanAttribute(Attribute.ENCRYPT);
encrypt.setBooleanValue(Boolean.TRUE);
wrapTemplate.addAttribute(encrypt);
BooleanAttribute decrypt = new BooleanAttribute(Attribute.DECRYPT);
decrypt.setBooleanValue(Boolean.TRUE);
wrapTemplate.addAttribute(decrypt);
//only keys matching the template can be wrapped
publicKeyTemplate.getWrapTemplate().setAttributeArrayValue(wrapTemplate);
publicKeyTemplate.getWrap().setBooleanValue(Boolean.TRUE);
Mechanism[] allowedMechanisms = new Mechanism[2];
Mechanism mechanism1 = new Mechanism(PKCS11Constants.CKM_RSA_PKCS);
allowedMechanisms[0] = mechanism1;
Mechanism mechanism2 = new Mechanism(PKCS11Constants.CKM_SHA1_RSA_PKCS);
allowedMechanisms[1] = mechanism2;
//the key can only be used with the specified mechanisms (example for RSA)
publicKeyTemplate.getAllowedMechanisms().setMechanismAttributeArrayValue(
allowedMechanisms);
}
} catch (TokenException te) {
//ignore
}
}
AlgorithmParameterSpec keyPairGenerationSpec;
if (algorithm.equalsIgnoreCase("DSA")) {
AlgorithmParameterGenerator parameterGenerator = AlgorithmParameterGenerator
.getInstance("DSA", "IAIK");
parameterGenerator.init(1024);
AlgorithmParameters parameters = parameterGenerator.generateParameters();
DSAParameterSpec parameterSpec = (DSAParameterSpec) parameters
.getParameterSpec(DSAParameterSpec.class);
keyPairGenerationSpec = (AlgorithmParameterSpec) new PKCS11KeyPairGenerationSpec(
parameterSpec, publicKeyTemplate, privateKeyTemplate)
.setUseUserRole(false);
} else if (algorithm.equalsIgnoreCase("DH")) {
// for DH a derivation key template is needed
privateKeyTemplate.getSign().setPresent(false);
publicKeyTemplate.getVerify().setPresent(false);
privateKeyTemplate.getDerive().setBooleanValue(Boolean.TRUE);
publicKeyTemplate.getDerive().setBooleanValue(Boolean.TRUE);
BigInteger p = new BigInteger(
"12589626212164087648142963156054693968143531724127210882720574876034885248674417543636718639332350307931351997411747275642172788678286702755019900752157141");
BigInteger g = new BigInteger(
"798714029407796779983910943217886294189424826995758502398002980609131374451706837327391684051692474365177068254749526220588451409333567287210386365320453");
AlgorithmParameterSpec parameterSpec = new DHParameterSpec(p, g);
keyPairGenerationSpec = (AlgorithmParameterSpec) new PKCS11KeyPairGenerationSpec(
parameterSpec, publicKeyTemplate, privateKeyTemplate)
.setUseUserRole(false);
} else {
// for RSA key length has to be specified
if (algorithm.equalsIgnoreCase("RSA")) {
((RSAPublicKey) publicKeyTemplate).getModulusBits().setLongValue(new Long(1024));
}
keyPairGenerationSpec = (AlgorithmParameterSpec) new PKCS11KeyPairGenerationSpec(
publicKeyTemplate, privateKeyTemplate).setUseUserRole(false);
}
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm,
pkcs11Provider_.getName());
keyPairGenerator.initialize(keyPairGenerationSpec);
keyPair_ = keyPairGenerator.generateKeyPair();
System.out.println(" finished");
}
/**
* This method prints the generated key-pair (<code>keyPair_</code>).
*/
public void printKeyPair(String algorithm) {
System.out
.println("################################################################################");
System.out.println("The generated " + algorithm + " key-pair is:");
if (keyPair_ == null) {
System.out.println("null");
} else {
System.out
.println("________________________________________________________________________________");
System.out.println("Public key:");
System.out.println(keyPair_.getPublic());
System.out
.println("________________________________________________________________________________");
System.out.println("Private key:");
System.out.println(keyPair_.getPrivate());
}
System.out
.println("################################################################################");
}
}
I had the same problem using a ACOS5, I solved this:
adjusting the required fields for the certificate ...: D
i'm sorrry i don't speak english
Mechanism keyPairGenerationMechanism = Mechanism.RSA_PKCS_KEY_PAIR_GEN;
RSAPublicKey rsaPublicKeyTemplate = new RSAPublicKey();
RSAPrivateKey rsaPrivateKeyTemplate = new RSAPrivateKey();
rsaPublicKeyTemplate.getObjectClass().setPresent(true);
rsaPublicKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getPrivate().setBooleanValue(Boolean.FALSE);
rsaPublicKeyTemplate.getModifiable().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getKeyType().setPresent(true);
byte[] id = new byte[5];
new Random().nextBytes(id);
rsaPublicKeyTemplate.getId().setByteArrayValue(id);
rsaPublicKeyTemplate.getLocal().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getKeyGenMechanism().setMechanism(keyPairGenerationMechanism);
rsaPublicKeyTemplate.getEncrypt().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getVerify().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getVerifyRecover().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getWrap().setBooleanValue(Boolean.TRUE);
byte[] mod = new byte[256];
new Random().nextBytes(mod);
rsaPublicKeyTemplate.getModulus().setByteArrayValue(mod);
rsaPublicKeyTemplate.getModulusBits().setLongValue(new Long(2048));
byte[] publicExponentBytes = { 0x01,0x00,0x01 }; // 2^16 + 1
rsaPublicKeyTemplate.getPublicExponent().setByteArrayValue(publicExponentBytes);
rsaPrivateKeyTemplate.getObjectClass().setPresent(true);
rsaPrivateKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getPrivate().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getModifiable().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getKeyType().setPresent(true);
rsaPrivateKeyTemplate.getId().setByteArrayValue(id);
rsaPrivateKeyTemplate.getLocal().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getKeyGenMechanism().setMechanism(keyPairGenerationMechanism);
rsaPrivateKeyTemplate.getSensitive().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getDecrypt().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getSignRecover().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getUnwrap().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getExtractable().setBooleanValue(Boolean.FALSE);
rsaPrivateKeyTemplate.getAlwaysSensitive().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getNeverExtractable().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getModulus().setByteArrayValue(mod);
rsaPrivateKeyTemplate.getPublicExponent().setByteArrayValue(publicExponentBytes);
the complete code for key pair geneation is
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package generatekeypair;
import iaik.pkcs.pkcs11.Mechanism;
import iaik.pkcs.pkcs11.MechanismInfo;
import iaik.pkcs.pkcs11.Module;
import iaik.pkcs.pkcs11.Session;
import iaik.pkcs.pkcs11.Slot;
import iaik.pkcs.pkcs11.Token;
import iaik.pkcs.pkcs11.TokenException;
import iaik.pkcs.pkcs11.TokenInfo;
import iaik.pkcs.pkcs11.objects.KeyPair;
import iaik.pkcs.pkcs11.objects.Object;
import iaik.pkcs.pkcs11.objects.RSAPrivateKey;
import iaik.pkcs.pkcs11.objects.RSAPublicKey;
import iaik.pkcs.pkcs11.wrapper.Functions;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author Administrador
*/
public class CrearCertiPar {
private Module pkcs11Module;
public CrearCertiPar(String librarayPath) throws TokenException {
try {
pkcs11Module = Module.getInstance(librarayPath);
pkcs11Module.initialize(null);
generarParcerti();
} catch (IOException ex) {
Logger.getLogger(CrearCertiPar.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void generarParcerti() throws TokenException {
Scanner teclado = new Scanner (System.in);
Slot[] slots = pkcs11Module.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
if (slots.length == 0) { //No tokens connected
System.out.println("Sorry, Couldn't find any token");
} else {
//Let's get the first slot
Slot selectedSlot = slots[0];
//Let's get the connected token
Token token = selectedSlot.getToken();
//Get the token infos
TokenInfo tokenInfo = token.getTokenInfo();
//System.out.println(tokenInfo);
Session session = token.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RW_SESSION, null, null);
//System.out.println(session);
if (tokenInfo.isLoginRequired()) {
if (tokenInfo.isProtectedAuthenticationPath()) {
session.login(Session.UserType.USER, null); // the token prompts the PIN by other means; e.g. PIN-pad
} else {
System.out.print("Enter user-PIN or press [return] to list just public objects: ");
System.out.flush();
//String userPINString = teclado.next();
String userPINString = "12345678";
System.out.println();
System.out.print("listing all" + ((userPINString.length() > 0) ? "" : " public") + " objects on token");
if (userPINString.length() > 0) {
// login user
session.login(Session.UserType.USER, userPINString.toCharArray());
}
}
}
System.out.println("############################# Generating new 1024 bit RSA key-pair ########################################");
HashSet supportedMechanisms = new HashSet(Arrays.asList(token.getMechanismList()));
MechanismInfo signatureMechanismInfo;
System.out.println("supportedMechanisms\n"+supportedMechanisms);
if (supportedMechanisms.contains(Mechanism.RSA_PKCS_KEY_PAIR_GEN)) {
signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_PKCS_KEY_PAIR_GEN);
} else if (supportedMechanisms.contains(Mechanism.RSA_X_509)) {
signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_X_509);
} else if (supportedMechanisms.contains(Mechanism.RSA_9796)) {
signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_9796);
} else if (supportedMechanisms.contains(Mechanism.RSA_PKCS_OAEP)) {
signatureMechanismInfo = token.getMechanismInfo(Mechanism.RSA_PKCS_OAEP);
} else {
signatureMechanismInfo = null;
}
// System.out.println("signatureMechanismInfo\n"+signatureMechanismInfo);
Mechanism keyPairGenerationMechanism = Mechanism.RSA_PKCS_KEY_PAIR_GEN;
RSAPublicKey rsaPublicKeyTemplate = new RSAPublicKey();
RSAPrivateKey rsaPrivateKeyTemplate = new RSAPrivateKey();
rsaPublicKeyTemplate.getObjectClass().setPresent(true);
rsaPublicKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getPrivate().setBooleanValue(Boolean.FALSE);
rsaPublicKeyTemplate.getModifiable().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getKeyType().setPresent(true);
byte[] id = new byte[5];
new Random().nextBytes(id);
rsaPublicKeyTemplate.getId().setByteArrayValue(id);
rsaPublicKeyTemplate.getLocal().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getKeyGenMechanism().setMechanism(keyPairGenerationMechanism);
rsaPublicKeyTemplate.getEncrypt().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getVerify().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getVerifyRecover().setBooleanValue(Boolean.TRUE);
rsaPublicKeyTemplate.getWrap().setBooleanValue(Boolean.TRUE);
byte[] mod = new byte[256];
new Random().nextBytes(mod);
rsaPublicKeyTemplate.getModulus().setByteArrayValue(mod);
rsaPublicKeyTemplate.getModulusBits().setLongValue(new Long(2048));
byte[] publicExponentBytes = { 0x01,0x00,0x01 }; // 2^16 + 1
rsaPublicKeyTemplate.getPublicExponent().setByteArrayValue(publicExponentBytes);
rsaPrivateKeyTemplate.getObjectClass().setPresent(true);
rsaPrivateKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getPrivate().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getModifiable().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getKeyType().setPresent(true);
rsaPrivateKeyTemplate.getId().setByteArrayValue(id);
rsaPrivateKeyTemplate.getLocal().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getKeyGenMechanism().setMechanism(keyPairGenerationMechanism);
rsaPrivateKeyTemplate.getSensitive().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getDecrypt().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getSignRecover().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getUnwrap().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getExtractable().setBooleanValue(Boolean.FALSE);
rsaPrivateKeyTemplate.getAlwaysSensitive().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getNeverExtractable().setBooleanValue(Boolean.TRUE);
rsaPrivateKeyTemplate.getModulus().setByteArrayValue(mod);
rsaPrivateKeyTemplate.getPublicExponent().setByteArrayValue(publicExponentBytes);
System.out.println("*********************************\n"+rsaPublicKeyTemplate);
System.out.println("*********************************\n");
System.out.println("*********************************\n"+rsaPrivateKeyTemplate);
System.out.println("*********************************\n");
KeyPair generatedKeyPair = session.generateKeyPair(keyPairGenerationMechanism,
rsaPublicKeyTemplate, rsaPrivateKeyTemplate);
// RSAPublicKey generatedRSAPublicKey = (RSAPublicKey) generatedKeyPair.getPublicKey();
// RSAPrivateKey generatedRSAPrivateKey = (RSAPrivateKey) generatedKeyPair
// .getPrivateKey();
// System.out.println("Success");
// System.out.println("The public key is");
// System.out.println("_______________________________________________________________________________");
// System.out.println(generatedRSAPublicKey);
// System.out.println("_______________________________________________________________________________");
// System.out.println("The private key is");
// System.out.println("_______________________________________________________________________________");
// System.out.println(generatedRSAPrivateKey);
// System.out.println("_______________________________________________________________________________");
//
}
}
}
bye... good luck
note: This product includes software developed by IAIK of Graz University of Technology."
Related
Im trying to import SecureRamdom in Java but
import java.security.SecureRandom;
isnt working. Im using Java SE 8 in Eclipse. Does anyone know how to import it?
Sure, it is possible.
Please, take a look at following code:
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author Momir Sarac
*/
public class SecureRandomExample {
public static void main(String[] args) {
try {
// obtain a strong SecureRandom implementation from securerandom.strongAlgorithms property of java.security.Security
// class
SecureRandom secureRandom = SecureRandom.getInstanceStrong();
// print the provided and algorithm obtained for this secureRandom
System.out.println("" + secureRandom.getProvider() + "\n" + secureRandom.getAlgorithm());
//generate 16-long seed bytes
//generate a given number of seed bytes (to seed other random number generators, for example):
byte[] bytes = secureRandom.generateSeed(16);
//print obtained bytes as string from array
System.out.println(Arrays.toString(bytes));
//to get random bytes, a caller simply passes an array of any length, which is then filled with random bytes:
secureRandom.nextBytes(bytes);
//print obtained bytes as string from array
System.out.println(Arrays.toString(bytes));
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(SecureRandomExample.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Turns out it does work. For some reason eclipse just highlighted it as an error even though it works.
As Adobe article "Digital Signatures in a PDF" stating:
PDF defines two types of signatures: approval and certification. The
differences are as follows:
Approval: There can be any number of approval signatures in a document. The field may optionally be associated with FieldMDP
permissions.
Certification: There can be only one certification signature and it must be the first one in a document. The field is always associated
with DocMDP.
Using PDFBox examples I was able to successfully apply multiple signatures to my document: https://github.com/apache/pdfbox/blob/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java
In order to apply multiple signatures I was just running same code multiple times with different signature placeholders and images.
But what I have distinguished is that, even though I am running same code it always sets first signature as Certified, and all other once as Approval.
But in my case, I don't want a document to be certified, I just need all signatures to be of Apploval type including the first one. I know I can invisible first Certifying signature, but still I do not want to certify document at all.
I was trying to find a way to setup signature, but couldn't figure it out.
Here is my usage of example code (other classes are in the GitHub link above):
public class SignnerPDFBoxExample extends CreateSignatureBase {
private SignatureOptions signatureOptions;
private PDVisibleSignDesigner visibleSignDesigner;
private final PDVisibleSigProperties visibleSignatureProperties = new PDVisibleSigProperties();
private boolean lateExternalSigning = false;
public static void main(String[] args) throws Exception {
File ksFile = new File("keystore.jks");
KeyStore keystore = KeyStore.getInstance("JKS");
char[] pin = "123456".toCharArray();
keystore.load(new FileInputStream(ksFile), pin);
SignnerPDFBoxExample signer = new SignnerPDFBoxExample(keystore, pin.clone());
String inputFilename = "Four_Signature_template.pdf";
File documentFile = new File(inputFilename);
File signedDocumentFile;
int page = 1;
try (FileInputStream imageStream = new FileInputStream("client_signature.jpg"))
{
String name = documentFile.getName();
String substring = name.substring(0, name.lastIndexOf('.'));
signedDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf");
// page is 1-based here
signer.setVisibleSignDesigner(inputFilename, 0, 0, -50, imageStream, page);
}
signer.setVisibleSignatureProperties("name", "location", "Signed using PDFBox", 0, page, true);
signer.signPDF(documentFile, signedDocumentFile, null, "certifySignature");
}
public boolean isLateExternalSigning()
{
return lateExternalSigning;
}
/**
* Set late external signing. Enable this if you want to activate the demo code where the
* signature is kept and added in an extra step without using PDFBox methods. This is disabled
* by default.
*
* #param lateExternalSigning
*/
public void setLateExternalSigning(boolean lateExternalSigning)
{
this.lateExternalSigning = lateExternalSigning;
}
/**
* Set visible signature designer for a new signature field.
*
* #param filename
* #param x position of the signature field
* #param y position of the signature field
* #param zoomPercent
* #param imageStream
* #param page the signature should be placed on
* #throws IOException
*/
public void setVisibleSignDesigner(String filename, int x, int y, int zoomPercent,
FileInputStream imageStream, int page)
throws IOException
{
visibleSignDesigner = new PDVisibleSignDesigner(filename, imageStream, page);
visibleSignDesigner.xAxis(x).yAxis(y).zoom(zoomPercent).adjustForRotation();
}
/**
* Set visible signature designer for an existing signature field.
*
* #param zoomPercent
* #param imageStream
* #throws IOException
*/
public void setVisibleSignDesigner(int zoomPercent, FileInputStream imageStream)
throws IOException
{
visibleSignDesigner = new PDVisibleSignDesigner(imageStream);
visibleSignDesigner.zoom(zoomPercent);
}
/**
* Set visible signature properties for new signature fields.
*
* #param name
* #param location
* #param reason
* #param preferredSize
* #param page
* #param visualSignEnabled
* #throws IOException
*/
public void setVisibleSignatureProperties(String name, String location, String reason, int preferredSize,
int page, boolean visualSignEnabled) throws IOException
{
visibleSignatureProperties.signerName(name).signerLocation(location).signatureReason(reason).
preferredSize(preferredSize).page(page).visualSignEnabled(visualSignEnabled).
setPdVisibleSignature(visibleSignDesigner);
}
/**
* Set visible signature properties for existing signature fields.
*
* #param name
* #param location
* #param reason
* #param visualSignEnabled
* #throws IOException
*/
public void setVisibleSignatureProperties(String name, String location, String reason,
boolean visualSignEnabled) throws IOException
{
visibleSignatureProperties.signerName(name).signerLocation(location).signatureReason(reason).
visualSignEnabled(visualSignEnabled).setPdVisibleSignature(visibleSignDesigner);
}
/**
* Initialize the signature creator with a keystore (pkcs12) and pin that
* should be used for the signature.
*
* #param keystore is a pkcs12 keystore.
* #param pin is the pin for the keystore / private key
* #throws KeyStoreException if the keystore has not been initialized (loaded)
* #throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found
* #throws UnrecoverableKeyException if the given password is wrong
* #throws CertificateException if the certificate is not valid as signing time
* #throws IOException if no certificate could be found
*/
public SignnerPDFBoxExample(KeyStore keystore, char[] pin)
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException, CertificateException
{
super(keystore, pin);
}
/**
* Sign pdf file and create new file that ends with "_signed.pdf".
*
* #param inputFile The source pdf document file.
* #param signedFile The file to be signed.
* #param tsaClient optional TSA client
* #throws IOException
*/
public void signPDF(File inputFile, File signedFile, TSAClient tsaClient) throws IOException
{
this.signPDF(inputFile, signedFile, tsaClient, null);
}
/**
* Sign pdf file and create new file that ends with "_signed.pdf".
*
* #param inputFile The source pdf document file.
* #param signedFile The file to be signed.
* #param tsaClient optional TSA client
* #param signatureFieldName optional name of an existing (unsigned) signature field
* #throws IOException
*/
public void signPDF(File inputFile, File signedFile, TSAClient tsaClient, String signatureFieldName) throws IOException
{
setTsaClient(tsaClient);
if (inputFile == null || !inputFile.exists())
{
throw new IOException("Document for signing does not exist");
}
// creating output document and prepare the IO streams.
FileOutputStream fos = new FileOutputStream(signedFile);
try (PDDocument doc = PDDocument.load(inputFile))
{
int accessPermissions = SigUtils.getMDPPermission(doc);
if (accessPermissions == 1)
{
throw new IllegalStateException("No changes to the document are permitted due to DocMDP transform parameters dictionary");
}
// Note that PDFBox has a bug that visual signing on certified files with permission 2
// doesn't work properly, see PDFBOX-3699. As long as this issue is open, you may want to
// be careful with such files.
PDSignature signature;
// sign a PDF with an existing empty signature, as created by the CreateEmptySignatureForm example.
signature = findExistingSignature(doc, signatureFieldName);
if (signature == null)
{
// create signature dictionary
signature = new PDSignature();
}
// Optional: certify
// can be done only if version is at least 1.5 and if not already set
// doing this on a PDF/A-1b file fails validation by Adobe preflight (PDFBOX-3821)
// PDF/A-1b requires PDF version 1.4 max, so don't increase the version on such files.
if (doc.getVersion() >= 1.5f && accessPermissions == 0)
{
SigUtils.setMDPPermission(doc, signature, 2);
}
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
if (acroForm != null && acroForm.getNeedAppearances())
{
// PDFBOX-3738 NeedAppearances true results in visible signature becoming invisible
// with Adobe Reader
if (acroForm.getFields().isEmpty())
{
// we can safely delete it if there are no fields
acroForm.getCOSObject().removeItem(COSName.NEED_APPEARANCES);
// note that if you've set MDP permissions, the removal of this item
// may result in Adobe Reader claiming that the document has been changed.
// and/or that field content won't be displayed properly.
// ==> decide what you prefer and adjust your code accordingly.
}
else
{
System.out.println("/NeedAppearances is set, signature may be ignored by Adobe Reader");
}
}
// default filter
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
// subfilter for basic and PAdES Part 2 signatures
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
if (visibleSignatureProperties != null)
{
// this builds the signature structures in a separate document
visibleSignatureProperties.buildSignature();
signature.setName(visibleSignatureProperties.getSignerName());
signature.setLocation(visibleSignatureProperties.getSignerLocation());
signature.setReason(visibleSignatureProperties.getSignatureReason());
}
// the signing date, needed for valid signature
signature.setSignDate(Calendar.getInstance());
// do not set SignatureInterface instance, if external signing used
SignatureInterface signatureInterface = isExternalSigning() ? null : this;
// register signature dictionary and sign interface
if (visibleSignatureProperties != null && visibleSignatureProperties.isVisualSignEnabled())
{
signatureOptions = new SignatureOptions();
signatureOptions.setVisualSignature(visibleSignatureProperties.getVisibleSignature());
signatureOptions.setPage(visibleSignatureProperties.getPage() - 1);
doc.addSignature(signature, signatureInterface, signatureOptions);
}
else
{
doc.addSignature(signature, signatureInterface);
}
if (isExternalSigning())
{
System.out.println("Signing externally " + signedFile.getName());
ExternalSigningSupport externalSigning = doc.saveIncrementalForExternalSigning(fos);
// invoke external signature service
byte[] cmsSignature = sign(externalSigning.getContent());
// Explanation of late external signing (off by default):
// If you want to add the signature in a separate step, then set an empty byte array
// and call signature.getByteRange() and remember the offset signature.getByteRange()[1]+1.
// you can write the ascii hex signature at a later time even if you don't have this
// PDDocument object anymore, with classic java file random access methods.
// If you can't remember the offset value from ByteRange because your context has changed,
// then open the file with PDFBox, find the field with findExistingSignature() or
// PODDocument.getLastSignatureDictionary() and get the ByteRange from there.
// Close the file and then write the signature as explained earlier in this comment.
if (isLateExternalSigning())
{
// this saves the file with a 0 signature
externalSigning.setSignature(new byte[0]);
// remember the offset (add 1 because of "<")
int offset = signature.getByteRange()[1] + 1;
// now write the signature at the correct offset without any PDFBox methods
try (RandomAccessFile raf = new RandomAccessFile(signedFile, "rw"))
{
raf.seek(offset);
raf.write(Hex.getBytes(cmsSignature));
}
}
else
{
// set signature bytes received from the service and save the file
externalSigning.setSignature(cmsSignature);
}
}
else
{
// write incremental (only for signing purpose)
doc.saveIncremental(fos);
}
}
// Do not close signatureOptions before saving, because some COSStream objects within
// are transferred to the signed document.
// Do not allow signatureOptions get out of scope before saving, because then the COSDocument
// in signature options might by closed by gc, which would close COSStream objects prematurely.
// See https://issues.apache.org/jira/browse/PDFBOX-3743
IOUtils.closeQuietly(signatureOptions);
}
// Find an existing signature (assumed to be empty). You will usually not need this.
private PDSignature findExistingSignature(PDDocument doc, String sigFieldName)
{
PDSignature signature = null;
PDSignatureField signatureField;
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
if (acroForm != null)
{
signatureField = (PDSignatureField) acroForm.getField(sigFieldName);
if (signatureField != null)
{
// retrieve signature dictionary
signature = signatureField.getSignature();
if (signature == null)
{
signature = new PDSignature();
// after solving PDFBOX-3524
// signatureField.setValue(signature)
// until then:
signatureField.getCOSObject().setItem(COSName.V, signature);
}
else
{
throw new IllegalStateException("The signature field " + sigFieldName + " is already signed.");
}
}
}
return signature;
}
/**
* This will print the usage for this program.
*/
private static void usage()
{
System.err.println("Usage: java " + CreateVisibleSignature.class.getName()
+ " <pkcs12-keystore-file> <pin> <input-pdf> <sign-image>\n" + "" +
"options:\n" +
" -tsa <url> sign timestamp using the given TSA server\n"+
" -e sign using external signature creation scenario");
}
}
Your signPDF method contains this code:
// Optional: certify
// can be done only if version is at least 1.5 and if not already set
// doing this on a PDF/A-1b file fails validation by Adobe preflight (PDFBOX-3821)
// PDF/A-1b requires PDF version 1.4 max, so don't increase the version on such files.
if (doc.getVersion() >= 1.5f && accessPermissions == 0)
{
SigUtils.setMDPPermission(doc, signature, 2);
}
If you don't want a certification signature to start with, remove this setMDPPermission call.
I'm making an application that captures the network trafic. I need to get the URL that the browser displays to the users and I thought I could use InetAddress to get the domain from the IP I had captured but It's not the same. For example, the domain I get from facebook.com is xx-fbcdn-shv-01-dft4.fbcdn.net and this is not always the same. Is there any other way to do it? Is it even possible?
I'm using JNetPCap library and the example code of it's page just to learn how to implement it in my proyect.
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jnetpcap.*;
import org.jnetpcap.packet.PcapPacket;
import org.jnetpcap.packet.PcapPacketHandler;
import org.jnetpcap.protocol.network.Ip4;
/**
*
* #author User
*/
public class Sniffer {
static private String device;
public static void main(String[] args) {
List<PcapIf> alldevs = new ArrayList<>(); // Will be filled with NICs
StringBuilder errbuf = new StringBuilder(); // For any error msgs
/**
* *************************************************************************
* First get a list of devices on this system
*************************************************************************
*/
int r = Pcap.findAllDevs(alldevs, errbuf);
if (r == Pcap.NOT_OK || alldevs.isEmpty()) {
System.err.printf("Can't read list of devices, error is %s", errbuf
.toString());
return;
}
System.out.println("Network devices found:");
int i = 0;
for (PcapIf device : alldevs) {
String description
= (device.getDescription() != null) ? device.getDescription()
: "No description available";
System.out.printf("#%d: %s [%s]\n", i++, device.getName(), description);
System.out.println(device.toString());
}
PcapIf device = alldevs.get(2);
/***************************************************************************
* Second we open up the selected device
**************************************************************************/
int snaplen = 64 * 1024; // Capture all packets, no trucation
int flags = Pcap.MODE_PROMISCUOUS; // capture all packets
int timeout = 10 * 1000; // 10 seconds in millis
Pcap pcap
= Pcap.openLive(device.getName(), snaplen, flags, timeout, errbuf);
if (pcap == null) {
System.err.printf("Error while opening device for capture: "
+ errbuf.toString());
return;
}
///*-------------------------------------------------------------------- ------------------------------
PcapBpfProgram program = new PcapBpfProgram();
String expression = "port 80";
int optimize = 0; // false
int netmask = 0xFFFFFF00; // 255.255.255.0
if (pcap.compile(program, expression, optimize, netmask) != Pcap.OK) {
System.err.println(pcap.getErr());
return;
}
if (pcap.setFilter(program) != Pcap.OK) {
System.err.println(pcap.getErr());
return;
}
///*
/**
* *************************************************************************
* Third we create a packet handler which will receive packets from the
* libpcap loop.
*************************************************************************
*/
PcapPacketHandler<String> jpacketHandler = (PcapPacket packet, String user) -> {
System.out.printf("Received packet at %s caplen=%-4d len=%-4d %s\n",
new Date(packet.getCaptureHeader().timestampInMillis()),
packet.getCaptureHeader().caplen(), // Length actually captured
packet.getCaptureHeader().wirelen(), // Original length
user // User supplied object
);
Ip4 ip = new Ip4();
//Tcp tcp= new Tcp();
byte[] sIP;
if (packet.hasHeader(ip)) {
try {
sIP = packet.getHeader(ip).source();
String sourceIP = org.jnetpcap.packet.format.FormatUtils.ip(sIP);
String myIp = InetAddress.getLocalHost().getHostAddress();
if (!myIp.equals(sourceIP)) {
System.out.println("source= "+sourceIP);
String domain;
domain = InetAddress.getByName(sourceIP).getHostName();
System.out.println("--------------------------"+domain);
}
} catch (UnknownHostException ex) {
Logger.getLogger(Sniffer.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
/**
* *************************************************************************
* Fourth we enter the loop and tell it to capture 10 packets. The loop
* method does a mapping of pcap.datalink() DLT value to JProtocol ID,
* which is needed by JScanner. The scanner scans the packet buffer and
* decodes the headers. The mapping is done automatically, although a
* variation on the loop method exists that allows the programmer to
* sepecify exactly which protocol ID to use as the data link type for
* this pcap interface.
*************************************************************************
*/
pcap.loop(-1, jpacketHandler, "jNetPcap rocks!");
/**
* *************************************************************************
* Last thing to do is close the pcap handle
*************************************************************************
*/
pcap.close();
}
}
You can't. Big sites got several addresses, so Facebook.com resolves to many addresses but reverse lookup of those addresses does not resolve to Facebook.com.
If you can capture the conversation you can read http headers, there you can find the url you are interested in.
I found a way to do it reading the tcp packets and using it's destination port. Thanks you for your help minus, I wouldn't find the solution without your help. This is the handler method.
static String dominios[] = {"com", "org", "net", "info", "biz", "edu", "gob"};
PcapPacketHandler<String> jpacketHandler = (PcapPacket packet, String user) -> {
Tcp tcp= new Tcp();
Http http= new Http();
if (packet.hasHeader(tcp)) {
if (tcp.destination() == 443) {
int payloadstart = tcp.getOffset() + tcp.size();
JBuffer buffer = new JBuffer(64 * 1024);
buffer.peer(packet, payloadstart, packet.size() - payloadstart);
String payload = buffer.toHexdump(packet.size(), false, true, true);
for (String b : dominios) {
if (payload.contains(b)) {
procesarTcp(payload, b);
}
}
}
else if(packet.hasHeader(http)){
System.out.println(http.fieldValue(Http.Request.Host));
}
}
};
public static void procesarTcp(String payload, String dominio) {
payload= payload.substring(0,payload.indexOf(dominio)+dominio.length());
StringTokenizer token= new StringTokenizer(payload,"\n");
String pagina;
String aux;
payload="";
while(token.hasMoreTokens()){
aux=token.nextToken();
payload+=aux.substring(aux.indexOf(" ")+4, aux.length());
}
pagina= payload.substring(payload.lastIndexOf("..")+2,payload.length());
System.err.println(pagina);
}
My goal is to extract and process any JavasSript code that a PDF document might contain. By opening a PDF in editor I can see objects like this:
402 0 obj
<</S/JavaScript/JS(\n\r\n /* Set day 25 */\r\n FormRouter_SetCurrentDate\("25"\);\r)>>
endobj
I am trying to use Apache PDFBox to accomplish this but so far with no luck.
This line returns an empty list:
jsObj = doc.getObjectsByType(COSName.JAVA_SCRIPT);
Can anyone can give me some direction?
This tool is based on the PrintFields example in PDFBox. It will show the Javascript fields in forms. I wrote it last year for a guy who had problems with relationship between AcroForm fields (some fields were enabled / disabled depending on the values of other fields). There are still other places where there can be Javascript.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package pdfboxpageimageextraction;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript;
import org.apache.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDNonTerminalField;
import org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField;
/**
* This example will take a PDF document and print all the fields from the file.
*
* #author Ben Litchfield
*
*/
public class PrintJavaScriptFields
{
/**
* This will print all the fields from the document.
*
* #param pdfDocument The PDF to get the fields from.
*
* #throws IOException If there is an error getting the fields.
*/
public void printFields(PDDocument pdfDocument) throws IOException
{
PDDocumentCatalog docCatalog = pdfDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
List<PDField> fields = acroForm.getFields();
//System.out.println(fields.size() + " top-level fields were found on the form");
for (PDField field : fields)
{
processField(field, "|--", field.getPartialName());
}
}
private void processField(PDField field, String sLevel, String sParent) throws IOException
{
String partialName = field.getPartialName();
if (field instanceof PDTerminalField)
{
PDTerminalField termField = (PDTerminalField) field;
PDFormFieldAdditionalActions fieldActions = field.getActions();
if (fieldActions != null)
{
System.out.println(field.getFullyQualifiedName() + ": " + fieldActions.getClass().getSimpleName() + " js field actionS:\n" + fieldActions.getCOSObject());
printPossibleJS(fieldActions.getK());
printPossibleJS(fieldActions.getC());
printPossibleJS(fieldActions.getF());
printPossibleJS(fieldActions.getV());
}
for (PDAnnotationWidget widgetAction : termField.getWidgets())
{
PDAction action = widgetAction.getAction();
if (action instanceof PDActionJavaScript)
{
System.out.println(field.getFullyQualifiedName() + ": " + action.getClass().getSimpleName() + " js widget action:\n" + action.getCOSObject());
printPossibleJS(action);
}
}
}
if (field instanceof PDNonTerminalField)
{
if (!sParent.equals(field.getPartialName()))
{
if (partialName != null)
{
sParent = sParent + "." + partialName;
}
}
//System.out.println(sLevel + sParent);
for (PDField child : ((PDNonTerminalField) field).getChildren())
{
processField(child, "| " + sLevel, sParent);
}
}
else
{
String fieldValue = field.getValueAsString();
StringBuilder outputString = new StringBuilder(sLevel);
outputString.append(sParent);
if (partialName != null)
{
outputString.append(".").append(partialName);
}
outputString.append(" = ").append(fieldValue);
outputString.append(", type=").append(field.getClass().getName());
//System.out.println(outputString);
}
}
private void printPossibleJS(PDAction kAction)
{
if (kAction instanceof PDActionJavaScript)
{
PDActionJavaScript jsAction = (PDActionJavaScript) kAction;
String jsString = jsAction.getAction();
if (!jsString.contains("\n"))
{
// avoid display problems with netbeans
jsString = jsString.replaceAll("\r", "\n").replaceAll("\n\n", "\n");
}
System.out.println(jsString);
System.out.println();
}
}
/**
* This will read a PDF file and print out the form elements. <br />
* see usage() for commandline
*
* #param args command line arguments
*
* #throws IOException If there is an error importing the FDF document.
*/
public static void main(String[] args) throws IOException
{
PDDocument pdf = null;
try
{
pdf = PDDocument.load(new File("XXXX", "YYYYY.pdf"));
PrintJavaScriptFields exporter = new PrintJavaScriptFields();
exporter.printFields(pdf);
}
finally
{
if (pdf != null)
{
pdf.close();
}
}
}
}
As a bonus, here's code to show all COSString objects:
public class ShowAllCOSStrings
{
static Set<COSString> strings = new HashSet<COSString>();
static void crawl(COSBase base)
{
if (base instanceof COSString)
{
strings.add((COSString)base);
return;
}
if (base instanceof COSDictionary)
{
COSDictionary dict = (COSDictionary) base;
for (COSName key : dict.keySet())
{
crawl(dict.getDictionaryObject(key));
}
return;
}
if (base instanceof COSArray)
{
COSArray ar = (COSArray) base;
for (COSBase item : ar)
{
crawl(item);
}
return;
}
if (base instanceof COSNull ||
base instanceof COSObject ||
base instanceof COSName ||
base instanceof COSNumber ||
base instanceof COSBoolean ||
base == null)
{
return;
}
System.out.println("huh? " + base);
}
public static void main(String[] args) throws IOException
{
PDDocument doc = PDDocument.load(new File("XXX","YYY.pdf"));
for (COSObject obj : doc.getDocument().getObjects())
{
COSBase base = obj.getObject();
//System.out.println(obj + ": " + base);
crawl(base);
}
System.out.println(strings.size() + " strings:");
for (COSString s : strings)
{
String str = s.getString();
if (!str.contains("\n"))
{
// avoid display problems with netbeans
str = str.replaceAll("\r", "\n").replaceAll("\n\n", "\n");
}
System.out.println(str);
}
doc.close();
}
}
However Javascript can also be in a stream. See in the PDF spec "Additional entries specific to a rendition action", the JS entry:
A text string or stream containing a JavaScript script that shall be
executed when the action is triggered.
You can change the code above to catch COSStream objects too; COSStream is extended from COSDictionary.
We've been trying to calculate the Amazon Signature for the past few days using the Java code provided on Amazon's site.
I'm not a seasoned Java developer, but we've managed to use the basis of their code found at http://docs.developer.amazonservices.com/en_US/dev_guide/DG_ClientLibraries.html#DG_OwnClientLibrary__Signatures to generate a signature but we keep getting a "signature doesn't match" error that we're running into a wall debugging. Here is our current Java code with account specific information omitted:
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import java.sql.*;
import java.util.Date;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Date;
public class Main {
private static final String CHARACTER_ENCODING = "UTF-8";
final static String ALGORITHM = "HmacSHA256";
public static void main(String[] args) throws Exception {
// Change this secret key to yours
String secretKey = "XXXXXXXXXXXXXXXXXXXXXX"; // This secret key does have a forward slash in it (3rd to last character), would that adversely affect anything?
// Use the endpoint for your marketplace
String serviceUrl = "https://mws.amazonservices.com/Orders/2011-01-01";
// Create set of parameters needed and store in a map
HashMap<String, String> parameters = new HashMap<String,String>();
// Add required parameters. Change these as needed.
parameters.put("AWSAccessKeyId", urlEncode("XXXXXXXXXXX"));
parameters.put("Action", urlEncode("ListOrders"));
parameters.put("MarketplaceId.Id.1", urlEncode("ATVPDKIKX0DER"));
parameters.put("Merchant", urlEncode("ALZYDHGPLQNLD"));
parameters.put("OrderStatus.Status.1", urlEncode("PartiallyShipped"));
parameters.put("OrderStatus.Status.2", urlEncode("Unshipped"));
parameters.put("SignatureMethod", urlEncode(ALGORITHM));
parameters.put("SignatureVersion", urlEncode("2"));
parameters.put("Timestamp", urlEncode("2014-01-29T22:11:00Z"));
parameters.put("Version", urlEncode("2011-01-01"));
//parameters.put("SubmittedFromDate", urlEncode("2014-01-28T15:05:00Z"));
// Format the parameters as they will appear in final format
// (without the signature parameter)
String formattedParameters = calculateStringToSignV2(parameters, serviceUrl);
//System.out.println(formattedParameters);
String signature = sign(formattedParameters, secretKey);
System.out.println(urlEncode(signature));
// Add signature to the parameters and display final results
parameters.put("Signature", urlEncode(signature));
System.out.println(calculateStringToSignV2(parameters, serviceUrl));
// TEST AREA
// Signiture sig = new Signiture();
// String HMAC = sig.calculateRFC2104HMAC(parameters, secretKey);
// TEST AREA
}
/* If Signature Version is 2, string to sign is based on following:
*
* 1. The HTTP Request Method followed by an ASCII newline (%0A)
*
* 2. The HTTP Host header in the form of lowercase host,
* followed by an ASCII newline.
*
* 3. The URL encoded HTTP absolute path component of the URI
* (up to but not including the query string parameters);
* if this is empty use a forward '/'. This parameter is followed
* by an ASCII newline.
*
* 4. The concatenation of all query string components (names and
* values) as UTF-8 characters which are URL encoded as per RFC
* 3986 (hex characters MUST be uppercase), sorted using
* lexicographic byte ordering. Parameter names are separated from
* their values by the '=' character (ASCII character 61), even if
* the value is empty. Pairs of parameter and values are separated
* by the '&' character (ASCII code 38).
*
*/
private static String calculateStringToSignV2(Map<String, String> parameters, String serviceUrl)
throws SignatureException, URISyntaxException {
// Sort the parameters alphabetically by storing
// in TreeMap structure
Map<String, String> sorted = new TreeMap<String, String>();
sorted.putAll(parameters);
// Set endpoint value
URI endpoint = new URI(serviceUrl.toLowerCase());
// Create flattened (String) representation
StringBuilder data = new StringBuilder();
/*data.append("POST\n");
data.append(endpoint.getHost());
data.append("\n/");
data.append("\n");*/
Iterator<Entry<String, String>> pairs = sorted.entrySet().iterator();
while (pairs.hasNext()) {
Map.Entry<String, String> pair = pairs.next();
if (pair.getValue() != null) {
data.append( pair.getKey() + "=" + pair.getValue());
}
else {
data.append( pair.getKey() + "=");
}
// Delimit parameters with ampersand (&)
if (pairs.hasNext()) {
data.append( "&");
}
}
return data.toString();
}
/*
* Sign the text with the given secret key and convert to base64
*/
private static String sign(String data, String secretKey)
throws NoSuchAlgorithmException, InvalidKeyException,
IllegalStateException, UnsupportedEncodingException {
Mac mac = Mac.getInstance(ALGORITHM);
//System.out.println(mac);//
mac.init(new SecretKeySpec(secretKey.getBytes(CHARACTER_ENCODING), ALGORITHM));
//System.out.println(mac);//
byte[] signature = mac.doFinal(data.getBytes(CHARACTER_ENCODING));
//System.out.println(signature);//
String signatureBase64 = new String(Base64.encodeBase64(signature), CHARACTER_ENCODING);
System.out.println(signatureBase64);
return new String(signatureBase64);
}
private static String urlEncode(String rawValue) {
String value = (rawValue == null) ? "" : rawValue;
String encoded = null;
try {
encoded = URLEncoder.encode(value, CHARACTER_ENCODING)
.replace("+", "%20")
.replace("*", "%2A")
.replace("%7E","~");
} catch (UnsupportedEncodingException e) {
System.err.println("Unknown encoding: " + CHARACTER_ENCODING);
e.printStackTrace();
}
return encoded;
}
}
Right now we're testing this by hand because I'm trying to submit requests/manage the data through a Filemaker Database, so I may be adding the signature back to the URL query incorrectly. I'm assuming that 1) all of the parameters need to be listed in the query alphabetically and 2) the signature is the only exception that gets appended, last.
For example:
AWSAccessKeyId=AKIAITPQPJO62G4LAE7Q&Action=ListOrders&MarketplaceId.Id.1=XXXXXXXXXXX&Merchant=XXXXXXXXXXX&OrderStatus.Status.1=PartiallyShipped&OrderStatus.Status.2=Unshipped&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2014-01-29T22%3A11%3A00Z&Version=2011-01-01&Signature=tNufJeONZlscTlHs%2FLAWBs7zwsfpIaQcUK%2B5XIPJpcQ%3D
But the response I keep getting is this:
<?xml version="1.0"?>
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2011-01-01">
<Error>
<Type>Sender</Type>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
</Error>
<RequestID>7532e668-c660-4db6-b129-f5fe5d3fad63</RequestID>
</ErrorResponse>
Any insight would be greatly appreciated. Debugging is fun but I need to get past this already!