Digital signatures - chapter 1
These examples were written in the context of Chapter 1 - "Understanding the concept of digital signatures" of the Digital Signatures for PDF documents eBook.
c1_01_digestdefault
An example showing how to use the MessageDigest class:
JAVA
JAVA
package com.itextpdf.samples.signatures.chapter01;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Arrays;
public class C1_01_DigestDefault {
public static final String DEST = "./target/test/resources/signatures/chapter01/";
public static final String EXPECTED_OUTPUT = "Digest using MD5: 16\n" +
"Digest: 5f4dcc3b5aa765d61d8327deb882cf99\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-1: 20\n" +
"Digest: 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-224: 28\n" +
"Digest: d63dc919e201d7bc4c825630d2cf25fdc93d4b2f0d46706d29038d01\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-256: 32\n" +
"Digest: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-384: 48\n" +
"Digest: a8b64babd0aca91a59bdbb7761b421d4f2bb38280d3a75ba0f21f2bebc4558" +
"3d446c598660c94ce680c47d19c30783a7\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-512: 64\n" +
"Digest: b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b" +
"1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"RIPEMD128 MessageDigest not available\n" +
"RIPEMD160 MessageDigest not available\n" +
"RIPEMD256 MessageDigest not available\n";
protected byte[] digest;
protected MessageDigest messageDigest;
protected C1_01_DigestDefault(String password, String algorithm, String provider) throws GeneralSecurityException,
UnsupportedEncodingException {
if (provider == null) {
messageDigest = MessageDigest.getInstance(algorithm);
} else {
messageDigest = MessageDigest.getInstance(algorithm, provider);
}
digest = messageDigest.digest(password.getBytes("UTF-8"));
}
public static C1_01_DigestDefault getInstance(String password, String algorithm) throws GeneralSecurityException,
UnsupportedEncodingException {
return new C1_01_DigestDefault(password, algorithm, null);
}
public static void main(String[] args) {
File file = new File(DEST);
file.mkdirs();
testAll();
}
public static void testAll() {
showTest("MD5");
showTest("SHA-1");
showTest("SHA-224");
showTest("SHA-256");
showTest("SHA-384");
showTest("SHA-512");
showTest("RIPEMD128");
showTest("RIPEMD160");
showTest("RIPEMD256");
}
public static void showTest(String algorithm) {
try {
C1_01_DigestDefault app = getInstance("password", algorithm);
System.out.println("Digest using " + algorithm + ": " + app.getDigestSize());
System.out.println("Digest: " + app.getDigestAsHexString());
System.out.println("Is the password 'password'? " + app.checkPassword("password"));
System.out.println("Is the password 'secret'? " + app.checkPassword("secret"));
} catch (Exception exc) {
System.out.println(exc.getMessage());
}
}
public int getDigestSize() {
return digest.length;
}
public String getDigestAsHexString() {
return new BigInteger(1, digest).toString(16);
}
/* This method checks if the digest of the password is equal
* to the digest of the text line which is passed as argument
*/
public boolean checkPassword(String password) {
return Arrays.equals(digest, messageDigest.digest(password.getBytes()));
}
}
C#
C#
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Math;
namespace iText.Samples.Signatures.Chapter01
{
public class C1_01_DigestDefault
{
public static readonly String DEST = "results/signatures/chapter01/";
public static readonly String EXPECTED_OUTPUT = "Digest using MD5: 16\n" +
"Digest: 5f4dcc3b5aa765d61d8327deb882cf99\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"SHA-1 digest is not available\n" +
"SHA-224 digest is not available\n" +
"Digest using SHA-256: 32\n" +
"Digest: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using SHA-384: 48\n" +
"Digest: a8b64babd0aca91a59bdbb7761b421d4f2bb38280d3a75ba0f21f" +
"2bebc45583d446c598660c94ce680c47d19c30783a7\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using SHA-512: 64\n" +
"Digest: b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394" +
"c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"RIPEMD128 digest is not available\n" +
"Digest using RIPEMD160: 20\n" +
"Digest: 2c08e8f5884750a7b99f6f2f342fc638db25ff31\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"RIPEMD256 digest is not available\n";
protected byte[] digest;
protected HashAlgorithm messageDigest;
protected C1_01_DigestDefault(String password, String algorithm)
{
messageDigest = HashAlgorithm.Create(algorithm);
if (null == messageDigest)
{
throw new ArgumentException(algorithm + " digest is not available\n");
}
digest = messageDigest.ComputeHash(Encoding.UTF8.GetBytes(password));
}
public static C1_01_DigestDefault GetInstance(String password, String algorithm)
{
return new C1_01_DigestDefault(password, algorithm);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
TestAll();
}
public static void TestAll()
{
ShowTest("MD5");
ShowTest("SHA-1");
ShowTest("SHA-224");
ShowTest("SHA-256");
ShowTest("SHA-384");
ShowTest("SHA-512");
ShowTest("RIPEMD128");
ShowTest("RIPEMD160");
ShowTest("RIPEMD256");
}
public static void ShowTest(String algorithm)
{
try
{
C1_01_DigestDefault app = GetInstance("password", algorithm);
Console.WriteLine("Digest using " + algorithm + ": " + app.GetDigestSize());
Console.WriteLine("Digest: " + app.GetDigestAsHexString());
Console.WriteLine("Is the password 'password'? " + app.CheckPassword("password"));
Console.WriteLine("Is the password 'secret'? " + app.CheckPassword("secret"));
}
catch (ArgumentException exc)
{
Console.WriteLine(exc.Message);
}
}
public int GetDigestSize()
{
return digest.Length;
}
public String GetDigestAsHexString()
{
return new BigInteger(1, digest).ToString(16);
}
// This method checks if the digest of the password is equal
// to the digest of the text line which is passed as argument
public bool CheckPassword(String password)
{
return digest.SequenceEqual(messageDigest.ComputeHash(Encoding.UTF8.GetBytes(password)));
}
}
}
c1_02_digestbc
An example demonstrating the use of the Bouncy Castle library:
JAVA
JAVA
package com.itextpdf.samples.signatures.chapter01;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.Provider;
import java.util.Arrays;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class C1_02_DigestBC {
public static final String DEST = "./target/test/resources/signatures/chapter01/";
public static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
public static final String EXPECTED_OUTPUT = "Digest using MD5: 16\n" +
"Digest: 5f4dcc3b5aa765d61d8327deb882cf99\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-1: 20\n" +
"Digest: 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-224: 28\n" +
"Digest: d63dc919e201d7bc4c825630d2cf25fdc93d4b2f0d46706d29038d01\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-256: 32\n" +
"Digest: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-384: 48\n" +
"Digest: a8b64babd0aca91a59bdbb7761b421d4f2bb38280d3a75ba0f21f2bebc45583d446c" +
"598660c94ce680c47d19c30783a7\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using SHA-512: 64\n" +
"Digest: b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7" +
"785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using RIPEMD128: 16\n" +
"Digest: c9c6d316d6dc4d952a789fd4b8858ed7\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using RIPEMD160: 20\n" +
"Digest: 2c08e8f5884750a7b99f6f2f342fc638db25ff31\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n" +
"Digest using RIPEMD256: 32\n" +
"Digest: f94cf96c79103c3ccad10d308c02a1db73b986e2c48962e96ecd305e0b80ef1b\n" +
"Is the password 'password'? true\n" +
"Is the password 'secret'? false\n";
protected byte[] digest;
protected MessageDigest messageDigest;
protected C1_02_DigestBC(String password, String algorithm, Provider provider) throws GeneralSecurityException,
UnsupportedEncodingException {
if (provider == null) {
messageDigest = MessageDigest.getInstance(algorithm);
} else {
// BouncyCastle provider can be initialized in another way
// by using Security.addProvider(Provider provider) method
messageDigest = MessageDigest.getInstance(algorithm, provider);
}
digest = messageDigest.digest(password.getBytes("UTF-8"));
}
public static C1_02_DigestBC getInstance(String password, String algorithm) throws GeneralSecurityException,
UnsupportedEncodingException {
return new C1_02_DigestBC(password, algorithm, PROVIDER);
}
public static void main(String[] args) throws Exception {
File file = new File(DEST);
file.mkdirs();
testAll();
}
public static void testAll() throws Exception {
showTest("MD5");
showTest("SHA-1");
showTest("SHA-224");
showTest("SHA-256");
showTest("SHA-384");
showTest("SHA-512");
showTest("RIPEMD128");
showTest("RIPEMD160");
showTest("RIPEMD256");
}
public static void showTest(String algorithm) throws Exception {
C1_02_DigestBC app = getInstance("password", algorithm);
System.out.println("Digest using " + algorithm + ": " + app.getDigestSize());
System.out.println("Digest: " + app.getDigestAsHexString());
System.out.println("Is the password 'password'? " + app.checkPassword("password"));
System.out.println("Is the password 'secret'? " + app.checkPassword("secret"));
}
public int getDigestSize() {
return digest.length;
}
public String getDigestAsHexString() {
return new BigInteger(1, digest).toString(16);
}
/* This method checks if the digest of the password is equal
* to the digest of the text line which is passed as argument
*/
public boolean checkPassword(String password) {
return Arrays.equals(digest, messageDigest.digest(password.getBytes()));
}
}
C#
C#
using System;
using System.IO;
using System.Linq;
using System.Text;
using iText.Commons.Bouncycastle.Crypto;
using iText.Signatures;
using Org.BouncyCastle.Math;
namespace iText.Samples.Signatures.Chapter01
{
public class C1_02_DigestBC
{
public static readonly String DEST = "results/signatures/chapter01/";
public static readonly String EXPECTED_OUTPUT = "Digest using MD5: 16\n" +
"Digest: 5f4dcc3b5aa765d61d8327deb882cf99\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using SHA-1: 20\n" +
"Digest: 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using SHA-224: 28\n" +
"Digest: d63dc919e201d7bc4c825630d2cf25fdc93d4b2f0d46706d29038d01\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using SHA-256: 32\n" +
"Digest: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using SHA-384: 48\n" +
"Digest: a8b64babd0aca91a59bdbb7761b421d4f2bb38280d3a75ba0f21f2" +
"bebc45583d446c598660c94ce680c47d19c30783a7\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using SHA-512: 64\n" +
"Digest: b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394" +
"c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using RIPEMD128: 16\n" +
"Digest: c9c6d316d6dc4d952a789fd4b8858ed7\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using RIPEMD160: 20\n" +
"Digest: 2c08e8f5884750a7b99f6f2f342fc638db25ff31\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n" +
"Digest using RIPEMD256: 32\n" +
"Digest: f94cf96c79103c3ccad10d308c02a1db73b986e2c48962e96ecd305e0b80ef1b\n" +
"Is the password 'password'? True\n" +
"Is the password 'secret'? False\n";
protected byte[] digest;
protected IDigest messageDigest;
protected C1_02_DigestBC(String password, String algorithm)
{
messageDigest = DigestAlgorithms.GetMessageDigest(algorithm);
digest = DigestAlgorithms.Digest(new MemoryStream(Encoding.UTF8.GetBytes(password)), messageDigest);
}
public static C1_02_DigestBC GetInstance(String password, String algorithm)
{
return new C1_02_DigestBC(password, algorithm);
}
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
TestAll();
}
public static void TestAll()
{
ShowTest("MD5");
ShowTest("SHA-1");
ShowTest("SHA-224");
ShowTest("SHA-256");
ShowTest("SHA-384");
ShowTest("SHA-512");
ShowTest("RIPEMD128");
ShowTest("RIPEMD160");
ShowTest("RIPEMD256");
}
public static void ShowTest(String algorithm)
{
C1_02_DigestBC app = GetInstance("password", algorithm);
Console.WriteLine("Digest using " + algorithm + ": " + app.GetDigestSize());
Console.WriteLine("Digest: " + app.GetDigestAsHexString());
Console.WriteLine("Is the password 'password'? " + app.CheckPassword("password"));
Console.WriteLine("Is the password 'secret'? " + app.CheckPassword("secret"));
}
public int GetDigestSize()
{
return digest.Length;
}
public String GetDigestAsHexString()
{
return new BigInteger(1, digest).ToString(16);
}
// This method checks if the digest of the password is equal
// to the digest of the text line which is passed as argument
public bool CheckPassword(String password)
{
return digest.SequenceEqual(DigestAlgorithms
.Digest(new MemoryStream(Encoding.UTF8.GetBytes(password)), messageDigest));
}
}
}
c1_03_encryptdecrypt
An example of a simple class to encrypt and decrypt messages:
JAVA
JAVA
package com.itextpdf.samples.signatures.chapter01;
import javax.crypto.Cipher;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.X509Certificate;
public class C1_03_EncryptDecrypt {
public static final String DEST = "./target/test/resources/signatures/chapter01/";
protected static final String KEYSTORE = "./src/test/resources/encryption/ks";
protected static final String PASSWORD = "password";
protected KeyStore ks;
public static void main(String[] args) throws Exception {
File file = new File(DEST);
file.mkdirs();
encryptDecrypt();
}
public static void encryptDecrypt() throws GeneralSecurityException, IOException {
C1_03_EncryptDecrypt app = new C1_03_EncryptDecrypt();
app.initKeyStore(KEYSTORE, PASSWORD);
Key publicKey = app.getPublicKey("demo");
Key privateKey = app.getPrivateKey("demo", "password");
// Encrypt the message with the public key and then decrypt it with the private key
System.out.println("Let's encrypt 'secret message' with a public key");
byte[] encrypted = app.encrypt(publicKey, "secret message");
System.out.println("Encrypted message: " + app.getDigestAsHexString(encrypted));
System.out.println("Let's decrypt it with the corresponding private key");
String decrypted = app.decrypt(privateKey, encrypted);
System.out.println(decrypted);
// Encrypt the message with the private key and then decrypt it with the public key
System.out.println("You can also encrypt the message with a private key");
encrypted = app.encrypt(privateKey, "secret message");
System.out.println("Encrypted message: " + app.getDigestAsHexString(encrypted));
System.out.println("Now you need the public key to decrypt it");
decrypted = app.decrypt(publicKey, encrypted);
System.out.println(decrypted);
}
private void initKeyStore(String keystore, String ks_pass) throws GeneralSecurityException, IOException {
ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(keystore), ks_pass.toCharArray());
}
private String getDigestAsHexString(byte[] digest) {
return new BigInteger(1, digest).toString(16);
}
private X509Certificate getCertificate(String alias) throws KeyStoreException {
return (X509Certificate) ks.getCertificate(alias);
}
private Key getPublicKey(String alias) throws GeneralSecurityException {
return getCertificate(alias).getPublicKey();
}
private Key getPrivateKey(String alias, String pk_pass) throws GeneralSecurityException {
return ks.getKey(alias, pk_pass.toCharArray());
}
// This method encrypts the message (using RSA algorithm) with the key, got as the 1st argument
public byte[] encrypt(Key key, String message) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherData = cipher.doFinal(message.getBytes());
return cipherData;
}
// This method decrypts the message (using RSA algorithm) with the key, got as the 1st argument
public String decrypt(Key key, byte[] message) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] cipherData = cipher.doFinal(message);
return new String(cipherData);
}
}
C#
C#
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
namespace iText.Samples.Signatures.Chapter01
{
public class C1_03_EncryptDecrypt
{
public static readonly String DEST = "results/signatures/chapter01/";
protected static readonly String KEYSTORE = "../../../resources/encryption/ks";
protected static readonly String PASSWORD = "password";
protected Pkcs12Store ks;
public static void Main(String[] args)
{
DirectoryInfo directory = new DirectoryInfo(DEST);
directory.Create();
EncryptDecrypt();
}
public static void EncryptDecrypt()
{
C1_03_EncryptDecrypt app = new C1_03_EncryptDecrypt();
app.InitKeyStore(KEYSTORE, PASSWORD);
AsymmetricKeyParameter publicKey = app.getPublicKey("demo");
AsymmetricKeyParameter privateKey = app.getPrivateKey("demo");
// Encrypt the message with the public key and then decrypt it with the private key
Console.WriteLine("Let's encrypt 'secret message' with a public key");
byte[] encrypted = app.Encrypt(publicKey, "secret message");
Console.WriteLine("Encrypted message: " + app.GetDigestAsHexString(encrypted));
Console.WriteLine("Let's decrypt it with the corresponding private key");
String decrypted = app.Decrypt(privateKey, encrypted);
Console.WriteLine(decrypted);
// Encrypt the message with the private key and then decrypt it with the public key
Console.WriteLine("You can also encrypt the message with a private key");
encrypted = app.Encrypt(privateKey, "secret message");
Console.WriteLine("Encrypted message: " + app.GetDigestAsHexString(encrypted));
Console.WriteLine("Now you need the public key to decrypt it");
decrypted = app.Decrypt(publicKey, encrypted);
Console.WriteLine(decrypted);
}
private void InitKeyStore(String keystore, String ks_pass)
{
ks =new Pkcs12StoreBuilder().Build();
ks.Load(new FileStream(keystore, FileMode.Open, FileAccess.Read),
ks_pass.ToCharArray());
}
private String GetDigestAsHexString(byte[] digest)
{
return new BigInteger(1, digest).ToString(16);
}
private X509Certificate GetCertificate(String alias)
{
return ks.GetCertificate(alias).Certificate;
}
private AsymmetricKeyParameter getPublicKey(String alias)
{
return GetCertificate(alias).GetPublicKey();
}
private AsymmetricKeyParameter getPrivateKey(String alias)
{
return ks.GetKey(alias).Key;
}
// This method encrypts the message (using RSA algorithm) with the key, got as the 1st argument
public byte[] Encrypt(AsymmetricKeyParameter key, String message)
{
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
Pkcs1Encoding encryptEngine = new Pkcs1Encoding(new RsaEngine());
// The first parameter defines whether to encrypt or decrypt
encryptEngine.Init(true, key);
return encryptEngine.ProcessBlock(messageBytes, 0, messageBytes.Length);
}
// This method decrypts the message (using RSA algorithm) with the key, got as the 1st argument
public String Decrypt(AsymmetricKeyParameter key, byte[] message)
{
Pkcs1Encoding decryptEngine = new Pkcs1Encoding(new RsaEngine());
// The first parameter defines whether to encrypt or decrypt
decryptEngine.Init(false, key);
return Encoding.UTF8.GetString(decryptEngine.ProcessBlock(message, 0, message.Length));
}
}
}