I want to sign a file I read in with JFileChooser
. But when I print it to the terminal I can only read questonmarks and other not human readable characters.
My code to sign is:
public static void sign() throws Exception{
byte[] file = fileChooser();
store = KeyStore.getInstance(storeType);
FileInputStream in = new FileInputStream(new File(storePath));
store.load(in, storePassword);
in.close();
Key priv = store.getKey("test", storePassword);
System.out.println(priv.toString() + "priv string");
X509Certificate cert = (X509Certificate) store.getCertificate("Subject");
ContentSigner signer = new JcaContentSignerBuilder("SHA512withRSA").build((RSAPrivateKey) priv);
//Sign Data
Signature signature = Signature.getInstance("SHA512WithRSA");
signature.initSign((RSAPrivateKey) priv);
signature.update(file);
//Build cms
CMSTypedData data = new CMSProcessableByteArray(signature.sign());
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().build())
.build(signer, cert));
//Get signed data
CMSSignedData sigData = gen.generate(data, false);
byte[] sig = (byte[]) sigData.getSignedContent().getContent();
sig.toString();
String content = new String(sig);
System.out.println("Signed content: " + content + "\n");
}
How can I format the signature to human readable?
The digital signature is an array of bytes that aren't in a human readable format, so creating a String
with it won't work as you expect.
If you want to have a "readable" format, you can encode it to Base64, using BouncyCastle's org.bouncycastle.util.encoders.Base64
class (I'm using BouncyCastle 1.56, but previous versions might have similar classes for Base64 conversion):
byte[] base64ByteArray = Base64.encode(sig); // sig is your byte array
String humanReadableString = new String(base64ByteArray); // human readable string
To get the original sig
array back, you must decode the humanReadableString
:
byte[] originalSigBytes = Base64.decode(humanReadableString.getBytes());
// originalSigBytes will be the same as sig
Notes: if you face any problem related to encoding, you can force the encoding with the java.nio.charset.Charset
class (in this example, I'm using UTF-8
but you can use whatever encoding your system uses):
// same thing as above, but using a specific encoding (UTF-8 in this case)
String humanReadableString = new String(base64ByteArray, Charset.forName("UTF-8"));
byte[] originalSigBytes = Base64.decode(humanReadableString.getBytes(Charset.forName("UTF-8")));
If you prefer, you can also convert to a Hex-encoded string (each byte becomes a string representation of its value in base 16), using BouncyCastle's org.bouncycastle.util.encoders.Hex
class:
byte[] hexEncodedArray = Hex.encode(sig);
String humanReadableString = new String(hexEncodedArray, Charset.forName("UTF-8"));
And to get your original sig
array back:
byte[] originalSigBytes = Hex.decode(humanReadableString.getBytes(Charset.forName("UTF-8")));
// originalSigBytes will be the same as sig
One more thing: when dealing with cryptography stuff, I suggest you to always manipulate the byte
array instead of converting them to String
. But if converting to a String
is mandatory, then use Base64 (or Hex-encoded string).