Can I get the type (RSA, DSA, ECDSA, ED25519...) or the fingerprint of a passphrase protected private SSH key without decrypting it with JSch (like you can in Linux with ssh-keygen -l -f <key_file>)?
I'm writing an Android app and JSch is pretty much the only lib that I managed to get to work with Android so it has to be done with JSch or manually.
Use KeyPair.load to load the key.
And then KeyPair.getKeyType and KeyPair.getFingerPrint to access its properties.
JSch jSch = new JSch();
KeyPair keypair = KeyPair.load(jSch, filename);
System.out.println(keypair.getKeyType());
System.out.println(keypair.getFingerPrint(jSch));
Martin Prikryl's answer is correct however I asked the question because I was getting IllegalStateException with the message encrypted key has not been decrypted yet. when I called getKeyType() so I thought that you can't get info about locked keys. After some more trial and error I found out that the problem was specific to the fork of JSch I use (com.github.mwiede:jsch:0.2.1) that adds support for ED25519 keys and the problem is specific to ED25519 keys. I solved my problem this way:
private static int getKeyType(Path keyFilePath) {
try {
Path keyFile = keyFilePath;
final byte[] key = Files.readAllBytes(keyFile);
final JSch jSch = new JSch();
final KeyPair keyPair = KeyPair.load(jSch, key, null);
return keyPair.getKeyType();
} catch (final IOException | JSchException e) {
System.err.println(e.getMessage());
return 0; // 0 is the key type of ERROR defined in the KeyPair class
} catch (IllegalStateException e) {
if (e.getMessage().equals("encrypted key has not been decrypted yet."))
return 5; // 5 is the key type of ED25519 defined in the KeyPair class
e.printStackTrace();
return 0;
}
}
I want to sign the pdf using pdf digest. I have created the hash using below code,
byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
md = MessageDigest.getInstance("SHA256","BC");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();
At the end I need to attach this signature to my pdf. I have found one solution Create pkcs7 signature from file digest, but the algorithm used in the link is SHA256withRSA. My privatekey is genearted using EC algorithm and I need to use SHA256withECDSA.Is it possible to just sign the Hash using SHA256withECDSA and attach the signature to the pdf using PDFBox ExternalSigning Interface.
There are several situations in which Adobe calls a signer's certificate invalid even though apparently it is valid; in the case at hand in particular:
Key usage or Extended key usage values not appropriate
PAdES signature misses an ESS signing-certificate-v2 attribute
Key usage or Extended key usage values not appropriate
This is based on the information the OP first published as an answer
I tried below code still the pdf says Signature is invalid. Can you please check the code,
[...]
I have attached the pdf . Pdf file created
Indeed, Adobe Reader says the signature is invalid, but look more closely:
It says "Document has not been modified since this signature was applied" - This means that the signature is mathematically correct!
The issue is that the "Signer's certificate is invalid", and the reason for this can be seen when digging into the signature property dialogues:
Thus, the problem is that your signer certificate is Not valid for usage.
This is due to the highlighted attribute, while the Key Usage Digital Signature is ok, the "Extended key usage" 1.3.6.1.5.5.8.2.2 (OID for IPSEC Protection) is not!
According to the Adobe Digital Signatures Guide for IT, Adobe Acrobat accepts only
one or more of the following Key usage values (if any)
nonRepudiation
signTransaction (11.0.09 only)
digitalSignature (11.0.10 and later)
and one or more of the following Extended key usage values (if any)
emailProtection
codeSigning
anyExtendedKeyUsage
1.2.840.113583.1.1.5 (Adobe Authentic Documents Trust)
Due to its IPSEC Protection extended key usage value, therefore, your certificate is not considered valid for signing PDF documents.
This probably only is an issue in legacy ISO 32000-1 signatures, probably not in PAdES signatures.
PAdES signature misses an ESS signing-certificate-v2 attribute
This is based on the information the OP first published as an answer
I have created 2 pdf files, PDFA is signed using the digest of the pdf content with below code,
[...]
PDFA
PDFB is created with the same private key and certificate, but instead of digest I am using pdf document content directly which gives me valid signed pdf, PDFB code below,
[...]
PDFB
I think something is missing in the signing part of PDFA which I couldn't figure out.
Here the main difference is not whether you explicitly calculate the hash yourself or allow it to be calculated implicitly, the main difference is that the signature in PDFB includes an ESS signing-certificate-v2 attribute while the one in PDFA does not. This attribute is generated between
//PAdES - PDF Advanced Electronic Signature
and
//PAdES-end
As the comments already hint, this is only necessary for PAdES signatures, not for legacy ISO 32000-1 ones. The answer the OP took his original code from referred to creating a legacy ISO 32000-1 signature (and, therefore, works alright) while the OP creates a PAdES signature.
The presence of an ESS signing certificate attribute is required by the PAdES specification ETSI EN 319 142-1:
e) Generators shall use either the signing certificate or the signing-certificate v2 attribute, depending on the hash function, in accordance with ETSI EN 319 122-1.
(ETSI EN 319 142-1, section 6.3 PAdES baseline signatures)
It references the CAdES specification ETSI EN 319 122-1 which in turn requires
h) Requirement for SPO: ESS signing-certificate. The ESS signing-certificate attribute shall be used if the SHA-1 hash algorithm is used.
i) Requirement for SPO: ESS signing-certificate-v2. The ESS signing-certificate-v2 attribute shall be used when another hash algorithms than SHA-1 is used.
(ETSI EN 319 122-1, section 6.3 Requirements on components and services)
I tried below code still the pdf says Signature is invalid. Can you please check the code,
System.out.println("Hash Signing started");
List<Certificate> certList = getFormatCertificate(strCertificate);
PrivateKey privateKey;
CMSSignedData s = null;
Security.addProvider(new BouncyCastleProvider());
byte[] signature = null;
try {
privateKey = loadPrivateKey(strPrivatekey);
byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
md = MessageDigest.getInstance("SHA256","BC");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();
// Separate signature container creation step
JcaCertStore certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
Attribute attr = new Attribute(CMSAttributes.messageDigest,
new DERSet(new DEROctetString(digest)));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
//AlgorithmIdentifier sha256withECDSA = new DefaultSignatureAlgorithmIdentifierFinder().find(signerAlgorithm);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certList.get(certList.size()-1).getEncoded());
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
gen.addSignerInfoGenerator(builder.build(
new JcaContentSignerBuilder(signerAlgorithm).build(privateKey),
new JcaX509CertificateHolder(cert)));
//DErse
// gen.addSignerInfoGenerator(builder.build(
// new JcaContentSignerBuilder(sha256withRSA,
// new DefaultDigestAlgorithmIdentifierFinder().find(sha256withRSA))
// .build(PrivateKeyFactory.createKey(privateKey.getEncoded())),
// new JcaX509CertificateHolder(cert)));
gen.addCertificates(certs);
s = gen.generate(new CMSAbsentContent(), false);
System.out.println("Hash sign completed");
signature = s.getEncoded();// ConstructEcdsaSigValue(s.getEncoded());
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("GeneralSecurityException ::"+e.toString());
} catch (OperatorCreationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("OperatorCreationException ::"+e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("IOException ::"+e.toString());
} catch (CMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("CMSException ::"+e.toString());
}finally{
return signature;
}
I have attached the pdf . Pdf file created
#Mkl/Tilman : I have created 2 pdf files, PDFA is signed using the digest of the pdf content with below code,
System.out.println("Hash Signing started");
List<Certificate> certList = getFormatCertificate(strCertificate);
PrivateKey privateKey;
CMSSignedData s = null;
Security.addProvider(new BouncyCastleProvider());
byte[] signature = null;
try {
privateKey = loadPrivateKey(strPrivatekey);
/*byte[] buffer = new byte[1024];
int numOfBytesRead =0;
MessageDigest md = null;
//md = MessageDigest.getInstance("SHA256","BC");
md = MessageDigest.getInstance("SHA-256");
while((numOfBytesRead = content.read(buffer)) != -1 ){
md.update(buffer, 0, numOfBytesRead);
}
byte[] digest = md.digest();*/
MessageDigest md = MessageDigest.getInstance("SHA256", "BC");
byte[] digest = md.digest(IOUtils.toByteArray(content));
// Separate signature container creation step
JcaCertStore certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
Attribute attr = new Attribute(CMSAttributes.messageDigest,
new DERSet(new DEROctetString(digest)));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
//AlgorithmIdentifier sha256withECDSA = new DefaultSignatureAlgorithmIdentifierFinder().find(signerAlgorithm);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certList.get(certList.size()-1).getEncoded());
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
gen.addSignerInfoGenerator(builder.build(
new JcaContentSignerBuilder(signerAlgorithm).build(privateKey),
new JcaX509CertificateHolder(cert)));
//DErse
// gen.addSignerInfoGenerator(builder.build(
// new JcaContentSignerBuilder(sha256withRSA,
// new DefaultDigestAlgorithmIdentifierFinder().find(sha256withRSA))
// .build(PrivateKeyFactory.createKey(privateKey.getEncoded())),
// new JcaX509CertificateHolder(cert)));
gen.addCertificates(certs);
s = gen.generate(new CMSAbsentContent(), false);
System.out.println("Hash sign completed");
signature = s.getEncoded();// ConstructEcdsaSigValue(s.getEncoded());
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("GeneralSecurityException ::"+e.toString());
} catch (OperatorCreationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("OperatorCreationException ::"+e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("IOException ::"+e.toString());
} catch (CMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("CMSException ::"+e.toString());
}finally{
return signature;
}
PDFA
PDFB is created with the same private key and certificate, but instead of digest I am using pdf document content directly which gives me valid signed pdf, PDFB code below,
SignatureInterface signatureInterface = new SignatureInterface() {
#SuppressWarnings("rawtypes")
#Override
public byte[] sign(InputStream content) throws IOException {
try {
byte[] certificateByte = null;
Store certs = new JcaCertStore(certificates);
//PAdES - PDF Advanced Electronic Signature
//ESS - Enhanced Security Services
//ASN1 - Abstract Syntax Notation One-standard interface description language for defining data structures that can be serialized and deserialized in a cross-platform way
// Generating certificate hash
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(certificates.get(certificates.size()-1).getEncoded());
byte[] certHash = md.digest();
// Generating certificate hash ends
System.out.println("Cert hash generated");
//ESSCertIDv2 identifies the certificate from the hash
ESSCertIDv2 essCert1 =
new ESSCertIDv2(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256), certHash);
ESSCertIDv2[] essCert1Arr =
{
essCert1
};
SigningCertificateV2 scv2 = new SigningCertificateV2(essCert1Arr);
Attribute certHAttribute =
new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(scv2));
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(certHAttribute);
AttributeTable at = new AttributeTable(v);
//Create a standard attribute table from the passed in parameters - certhash
CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(at){
protected Hashtable createStandardAttributeTable(Map parameters)
{
Hashtable result = super.createStandardAttributeTable(parameters);
result.remove(CMSAttributes.signingTime);
return result;
}
};
//PAdES-end
System.out.println("CMSAttributeTableGenerator generated");
SignerInfoGeneratorBuilder genBuild =
new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider());
genBuild.setSignedAttributeGenerator(attrGen);
//Get single certificate
org.spongycastle.asn1.x509.Certificate certas1 = org.spongycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificates.get(certificates.size()-1).getEncoded()));
// ContentSigner interface creates SHA256withECDSA signer using PvtKey
ContentSigner sha1Signer = new JcaContentSignerBuilder(signerAlgorithm).build(privateKey);
//Creates SignerInfoGenerator using X.509 cert and ContentSigner
SignerInfoGenerator sifGen = genBuild.build(sha1Signer, new X509CertificateHolder(certas1));
// CMSSignedDataGenerator generates a pkcs7-signature message
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addCertificates(certs);
gen.addSignerInfoGenerator(sifGen);
//Creates CMS message from PDF
CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
//Generate a CMS Signed Data object which can be carrying a detached CMS signature
//msg - content to be signed
CMSSignedData signedData = gen.generate(msg, false);
System.out.println("CMSSignedData is done");
return signedData.getEncoded();
} catch (GeneralSecurityException e) {
throw new IOException(e);
} catch (CMSException e) {
throw new IOException(e);
} catch (OperatorCreationException e) {
throw new IOException(e);
}
}
};
System.out.println("CMSSignedData is done2");
PDDocument pdDocument = PDDocument.load(inputfile);
System.out.println("pdDocument loaded");
pdDocument.addSignature(signature, signatureInterface);
PDFB
I think something is missing in the signing part of PDFA which I couldn't figure out.
I have an problem understanding how I am supposed to deal with emojis posted from users. I can see that the emoji is arriving to the SQLite database as an image (or font, or what?), but when selected from the database again, I get a question mark of course due to the database not understanding how it should deal with it.
Any enlightenment will do.
UPDATE
Well, utf-8 encoding/decoding was the answer just as the skilfull commenters have pointed.
My encoding:
String notes = mNotes.getText().toString();
try {
// Try to encode due to possible emojis in text
notes = URLEncoder.encode(mNotes.getText().toString(), "utf-8");
} catch (UnsupportedEncodingException ex) {
}
arguments.putString(WorkoutDataInputFragment.TEXT_EXTRA, notes);
My decoding:
try {
// Try to decode due to possible emojis in text
mMessage.setText(URLDecoder.decode(workout.message, "utf-8"));
} catch (UnsupportedEncodingException ex) {
mMessage.setText(workout.message);
}
I want to encrypt and decrypt the request and response of the web service(KSOAP or JSON) using SHA512 algorithm with private and public keys in android.
Does anyone have an idea on this. I don't have much experience on this. So please excuse me if i am wrong.
i guess the below class is used for encrypting a string. I want to know how to decrypt the string. And also i want to know how to use the private/public keys in this.
public class SHA2Demo {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String message = "test";
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
messageDigest.update(message.getBytes("UTF-16BE"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] digest = messageDigest.digest();
StringBuffer digestInHex = new StringBuffer();
for (int i = 0, l = digest.length; i < l; i++) {
// Preserve the bit representation when casting to integer.
int intRep = digest[i] & 0xFF;
// Add leading zero if value is less than 0x10.
if (intRep < 0x10) digestInHex.append('\u0030');
// Convert value to hex.
digestInHex.append(Integer.toHexString(intRep));
}
System.out.println(digestInHex.toString());
}
}
Thanks in advance.
Sha512 is a hash, not an encryption. You cannot encrypt anything with it. Use something like RSA or elliptic curves.
Sha512 is a hashing algorithm. You can NOT de-hash the response once it is hashed. That's what hash is for.
RSA or AES is what you might be looking for. Other things you may want to consider is Transport level security using SSL.
I'm new to android and security.
My app uses an encrypted DB which is encrypted by a private key. I want to find a way to store this private key in a protected place, without adding any additional password/pin code.
From what I've read, Android's keystore is the place to do it, but from my understanding, if I'll use it, it demands that I'll set a pin code for the device (which I don't want to do!).
Any suggestions regarding where to store this key and how? (any keystore related solution is acceptable as long as I don't have to set a pin code)
My direction is using some external open source keystore (any suggestions?) which I'll compile as part of my app (and because android doesn't share information between apps it will be ok to use).
I'm aware that my last assumption isn't correct when using a rooted device, but for my case I use only non-rooted devices.
I've searched a lot (here and else where) and couldn't find what I was looking for...
Any help is highly appreciated!!
10x
One thing you need to keep in mind is that the KeyChain isn't available until API 14. If you intend on targeting earlier API versions you need another option. You could use SpongyCastle to create your own KeyStore.
If you are not going to ask the user for a password you should at the very least obscure the password.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
KeyStore ks = null;
try {
ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null,null);
// Add certs or keys
ks.store(new FileOutputStream(new File(getFilesDir(),"out.bks")),"password".toCharArray());
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
static {
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}
}