Java Cryptography
Java Cryptographic Architecture
Java cryptography software comes in two sections.
JCA
-
The overall design of the cryptography classes is governed by the java cryptography architecture(JCA).
-
The JCA specify design patterns and extensible architecture for defining cryptographic concepts and algorithms.
-
These concepts(interfaces) are encapsulated by
java.security
andjavax.crypto
packages. -
Implementation ares supplied by cryptographic providers.
-
JDK1.2 comes with a default provider, named
SUN
. which implements a few cryptographic algorithms.
JCE
Java split its cryptography classes into two groups.
-
First group is included in the
java.security.*
packages that are part of JDK1.2. These classes can be exported without restriction. -
Second group, the Java Cryptography Extension, is for U.S and Canadian distribution only.
-
JCE is another extension of JCA and includes cryptographic provider called
SunJCE
. -
JCD is a standard extension library contains all its classes in
java.crypto.*
package.
Some classes in java.security are concerned with access control, security policy and permissions.
These are not directly related to cryptography.
|
Important classes
Below some of important classes from JCA and JCE
Details
Class or Interface | Description |
---|---|
java.security.cert.Certificate |
A cryptographic certificate |
javax.crypto.Cipher |
A cipher |
java.security.Key ,java.security.PrivateKey ,java.security.PublicKey ,javax.crypto.SecretKey |
A key, used for signing or encryption |
javax.crypto.KeyAgreement |
A secret key exchange protocol |
java.security.KeyFactory |
Translates public and private keys from one format to another |
javax.crypto.KeyGenerator |
Creates keys for symmetric ciphers |
java.security.KeyPairGenerator |
Creates pairs of public and private keys for signing or encryption |
javax.crypto.Mac |
A Message Authentication Code (MAC) |
java.security.MessageDigest |
A cryptographic hash function |
javax.crypto.SecretKeyFactory |
Translates secret keys from one format to another |
java.security.SecureRandom |
A cryptographically strong random number engine |
java.security.Signature |
A digital signature |
API and SPI
JCA classes divided into two groups.
-
Application Programming Interface(API):
It consists of all public methods that you can use to work with an instance of concept class.
java.security.Signature contains all API methods like verify .
|
-
Service Provider Interface (SPI):
Set of methods that subclasses must implement. SPI methods all begin withengine
.
java.security.SignatureSpi contains all SPI methods like engineVerify .
|
Providers will implement SPI interfaces. |
Factory Methods
JCA makes extensive use of factory methods to supply instances.
The following concepts classes have getInstance(algorithm, provider);
Class |
---|
javax.crypto.Cipher |
javax.crypto.KeyAgreement |
java.security.KeyFactory |
javax.crypto.KeyGenerator |
java.security.KeyPairGenerator |
javax.crypto.Mac |
java.security.MessageDigest |
javax.crypto.SecretKeyFactory |
java.security.Signature |
Provider Architecture
-
At the root of the JCA is the idea of security providers.
-
A provider supplies algorithms for the cryptographic concept classes.
-
Provider is a collection of algorithms headed up by
java.security.Provider
.
Configuring Provider
Providers can be configured in two ways.
-
Static Provider Configuration:
Edit$JAVA_HOME/jre/lib/security/java.security
properties file.
security.provider.1=sun.security.provider.Sun
security.provider.2=com.sun.crypto.provider.SunJCE
-
Runtime Provider Configuration:
Runtime provider configuration can be done usingSecurity.addProvider()
orSecurity.insertProviderAt()
.-
Security class has following important methods to manage providers.
-
Details
class Security{
/**
* Adds provider
* @param provider Provider
* @return position
*/
public static int addProvider(Provider provider);
/**
* Return Provider instance of given name
* @param name providerName
* @return null if name not found
*/
public static Provider getProvider(String name);
/**
* Returns arrays of providers
* @return array
*/
public static Provider[] getProviders();
/**
*
* @param provider Provider
* @param position position
* @return inserted position, already present return -1
*/
public static int insertProviderAt(Provider provider, int position);
/**
* Remove provider with name
* @param name providerName
*/
public static void removeProvider(String name);
}
-
Following Providers available by default in Mac Laptop
Provider | Information |
---|---|
SUN |
SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS & DKS keystores; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; JavaLoginConfig Configuration) |
SunRsaSign |
Sun RSA signature provider |
SunEC |
Sun Elliptic Curve provider (EC, ECDSA, ECDH) |
SunJSSE |
Sun JSSE provider(PKCS12, SunX509/PKIX key/trust factories, SSLv3/TLSv1/TLSv1.1/TLSv1.2) |
SunJCE |
SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC) |
SunJGSS |
Sun (Kerberos v5, SPNEGO) |
SunSASL |
Sun SASL provider(implements client mechanisms for: DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5, NTLM; server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM) |
XMLDSig |
XMLDSig (DOM XMLSignatureFactory; DOM KeyInfoFactory; C14N 1.0, C14N 1.1, Exclusive C14N, Base64, Enveloped, XPath, XPath2, XSLT TransformServices) |
SunPCSC |
Sun PC/SC provider |
Apple |
Apple Provider |
Random Number Generation
-
Random Numbers are important for strong cryptography.
-
Strong PRNG(Pseudo-random number generation) was introduced in JDK1.1 using
java.security.SecureRandom
that extendsjava.util.Random
.
Strong PRNG java.security.SecureRandom uses SHA-1 algorithm which produces 20 byte digest.
|
public class Main {
public static void main(String[] args) {
SecureRandom secureRandom = new SecureRandom(SecureRandom.getSeed(1024));
byte[] b =new byte[100];
secureRandom.nextBytes(b);
System.out.println(Base64.getEncoder().encodeToString(b));
}
}
Key Management
To exchange data securely, we need to keep track of our own private and public keys.
JCA has support for the key management using Identity
and KeyStore
classes.
Key Management Concepts included in the following classes and interfaces in the JDK.
Keys
The java.security.Key
interface encapsulates a cryptographic key.
It defines only three methods.
public class Key{
/**
* Returns name of cryptographic algorithm for which this key is used.
* Example: DSA(Digital Signature Algorithm)
* @return name
*/
public String getAlgorithm();
/**
* Returns encoded value of the key
* @return value
*/
public byte[] getEncoded();
/**
* Return name of the format used to encode the key. example X.509
* @return format
*/
public String getFormat();
}
-
Several interfaces extend this Key interface.
-
java.security.PublicKey: used to verify signature.
-
Ex: Signature.getInstance("").initVerify(publicKey )
-
java.security.PrivateKey: used to generate the signature
Ex: Signature.getInstance("").initSign(privateKey);
-
java.crypto.SecretKey: JCE includes another semantic extension of Key:
This is used for symmetric cipher. same key used for encrypt and decrypt.
-
java.security.KeyPair: encapsulates a matches public and private key.
public class KeyPair {
public PublicKey getPublic();
public PrivateKey getPrivate();
}
Key Generators
Key Generators are used to create new random keys which has following three steps.
-
Obtain a key generator object for the algorithm you want to use.
-
Initialize the key generator.
-
Ask the key generator to generator a key or key pair.
import javax.crypto.KeyGenerator;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
public class KeyGenerators {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
System.out.println(keyPair.getPrivate());
System.out.println(keyPair.getPublic());
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(new SecureRandom());
System.out.println(keyGenerator.generateKey());
}
}
Algorithm-Specific Initialization
Both KeyPairGenerator and KeyGenerator support the concept of
algorithm-specific initialization
.
-
Interface
java.security.spec.AlgorithmParameterSpec
defines no methods os constants. This of it as a box for parameters. you can pass AlgorithmParameterSpec to key generator to initializt it.
Key Translators
To transmit key over network or store on desk, following classes required.
-
SecretKeySpec : simplest way to convert array of bytes to a secret key is the
javax.crypto.spec.SecretKeySpec
.
public class Main {
public static void main(String[] args) throws Exception {
SecureRandom secureRandom = new SecureRandom();
byte[] ke = new byte[20];
secureRandom.nextBytes(ke);
SecretKey secretKey = new SecretKeySpec(ke, "HmacSHA1");
System.out.println(secretKey.getAlgorithm());
}
public SecretKey makeDESKey(byte[] input, int offset)
throws NoSuchAlgorithmException, InvalidKeyException,
InvalidKeySpecException {
SecretKeyFactory desFactory = SecretKeyFactory.getInstance("DES");
KeySpec spec = new DESKeySpec(input, offset);
return desFactory.generateSecret(spec);
}
public byte[] makeBytesFromDESKey(SecretKey key)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory desFactory = SecretKeyFactory.getInstance("DES");
DESKeySpec spec =
(DESKeySpec)desFactory.getKeySpec(key, DESKeySpec.class);
return spec.getKey();
}
}
-
SecretKeyFactory: for more complicated translation.
Key Agreement
Key agreement is a protocol whereby two or more parties can agree on a secret value. parties can agree on a secret value even while talking on an insecure medium. These protocol called key agreement protocol.
Diffie-Hellman
Most famous key agreement protocol is Diffie-Hellman(DH).
Message Digests
Message digests are one of the building blocks of digital signatures.
public class MessageDigest {
public static void main(String[] args) throws Exception {
MessageDigest messageDigest = MessageDigest.getInstance("SHA");
messageDigest.update(inputBytes);
byte[] digest= messageDigest.digest();
}
}
MAC
A message authentication code(MAC) is basically a keyed message digest.
MAC takes an arbitrary amount of input data and creates a short digest value.
Unlike MessageDigest , MAC uses key to create digest.
public class MACDemo {
public static void main(String[] args) throws Exception {
SecureRandom sr = new SecureRandom();
byte[] keyBytes = new byte[20];
sr.nextBytes(keyBytes);
SecretKey key = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac m = Mac.getInstance("HmacSHA1");
m.init(key);
m.update(inputData);
byte[] mac = m.doFinal();
}
}
Signatures
Signature is a message digest that is encrypted with the Signer’s private key. only public key can decrypt the signature.
If the message digest of the message matches the decrypted message digest from the signature, then integrity is also assured.
A Signature provides two security services.
-
authentication
-
integrity
Certificates
Certificate maintain authority of our secretKeys.
-
Several standards specify the contents of a certificate.
-
One of the most popular is X.509, published by the International Telecommunications Union (ITU).
Block Ciphers
Streams and Blocks
Symmetric ciphers come in two varieties.
-
Block ciphers: encrypt /decrypt fixed size blocks of data, usually 64 bits long
-
Stream ciphers: operate on a stream of bytes.
If you were encrypting the data between the client and server with a block cipher, you’d have to wait until the client typed enough characters to fill a block. In this case, a stream cipher is better suited to the task. |
-
Padding: The plaintext you wish to encrypt will not always be a multiple of block size (usually 64 bits). To compensate for the last incomplete block, padding is needed.
-
A padding scheme specifies exactly how the last block of plaintext is filled with data before is encrypted.
-
Corresponding procedure on the decryption side removes the padding and restores the plaintext orighinal length.
-
PKCS#5 is one possible padding scheme. Fill the remainder of the block with bytes containing the number of remaining bytes. |
-
Modes: the mode of cipher determines how blocks of plaintext are encrypted into blocks of ciphertext.
ECB, CBC, CFB, OFB, PCBC modes |
Cipher.getInstance("DES/ECB/PKCS5Padding");
Stream Ciphers
TBD
Encryption Algorithms & Cipher
Name | Provider |
---|---|
DES |
SunJCE, Cryptix, IAIK, JCP |
DESede |
SubJCE, Cryptix, IAIK, JCP |
PBEWIthMD5AndDES |
SunJCE |
RSA |
Cryptix, IAIK, JSAFE |
Blowfish |
Cryptix |
IDEA |
Cryptix |
SPEED |
Cryptix |
Cipher(Encryption)
javax.crypto.Cipher class encrypts and decrypts data.
It encapsulates a cipher algorithm.
It comes in three flavors.
-
Symmetric (singleKey)
-
Asymmetric (two keys)
-
Hybrid systems uses a combination of both.
public class CipherDemo {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
String inputString = "Codergists";
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate());
byte[] raw = cipher.doFinal(inputString.getBytes());
System.out.println("Encryption successful");
cipher.init(Cipher.DECRYPT_MODE, keyPair.getPublic());
System.out.println("Decrypted " + new String(cipher.doFinal(raw)));
System.out.println("Decryption Successful");
}
}
Feeding Data to a Cipher
A Cipher transforms one block of data into another block of data, either encrypting or decrypting. Two methods, update() and doFinal() , are used to feed data into the Cipher.
There are four overloaded versions of update():
public interface Cipher{
/**
*
* This method adds the given array of input data to the Cipher. If the Cipher has accumulated enough data to transform one or more blocks,
* it does so, returning the transformed blocks.
* Leftover data that does not fill an entire block is stored for use with the next call to update() or doFinal().
*/
public final byte[] update(byte[] input) throws IllegalStateException;
/**
* This method is the same as above, except that it uses inputLen bytes of the supplied byte array, starting at inputOffset.
*/
public final byte[] update(byte[] input, int inputOffset, int inputLen) throws IllegalStateException;
/**
* This method works like the previous method. The output, however, is written into the supplied output array.
* If the output array is too small to hold the results of the call to update(), a ShortBufferException is thrown. This method returns the total number of bytes that were written to the output array.
*/
public final int update(byte[] input, int inputOffset, int inputLen, byte[] output) throws IllegalStateException, ShortBufferException;
/**
* This method is the same as above, except that the output is written to the given output array, starting at outputOffset. As before, a ShortBufferException is thrown if there’s not enough space in the output array.
*/
public final int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws IllegalStateException, ShortBufferException;
public void demo(){
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plain5 = "comic".getBytes();
byte[] plain7 = "serious".getBytes();
byte[] step1 = cipher.update(plain5);
byte[] step2 = cipher.update(plain7);
}
}
Let’s see how update() works in practice. In the following examples, assume that we have already obtained a DES key.
The block size of a DES cipher is 8 bytes. In the first call to update(), we pass only 5 bytes, which is not enough for a full block.
-
Thus, no data is returned, and the length of the step1 array is 0. Our next call to update() adds 7 more bytes, for a total of 12.
-
This is enough to encrypt and return 1 block of data.
-
The step2 array is 8 bytes long and contains the first block of ciphertext.
-
What happened to the 4 leftover bytes?
The Cipher is still keeping track of them. * You can encrypt them, if they are the end of the plaintext, with the doFinal() methods.
Popular Providers
BouncyCastle Provider
BouncyCastle is a Java library that complements the default Java Cryptographic Extension (JCE).
-
Bouncy Castle Provider (FIPS Distribution): The FIPS 140-2 Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms certified to FIPS 140-2 level 1. This jar contains JCE provider and low-level API for the BC-FJA version 1.0.2.4, FIPS Certificate #4616. Please see certificate for certified platform details.
// https://mvnrepository.com/artifact/org.bouncycastle/bc-fips
implementation group: 'org.bouncycastle', name: 'bc-fips', version: '1.0.2.4'
-
Bouncy Castle Provider(bcprov-jdk18on): The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.8 and up.
// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk18on
implementation group: 'org.bouncycastle', name: 'bcprov-jdk18on', version: '1.77'
-
Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs:
The Bouncy Castle Java APIs for CMS, PKCS, EAC, TSP, CMP, CRMF, OCSP, and certificate generation. This jar contains APIs for JDK 1.8 and up. The APIs can be used in conjunction with a JCE/JCA provider such as the one provided with the Bouncy Castle Cryptography APIs.
// https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk18on
implementation group: 'org.bouncycastle', name: 'bcpkix-jdk18on', version: '1.77'
-
Bouncy Castle PKIX APIs (FIPS Distribution):
The Bouncy Castle Java APIs for CMS, PKCS, EAC, TSP, CMP, CRMF, OCSP, S/MIME and certificate generation. The APIs are designed primarily to be used in conjunction with the BC FIPS provider. The APIs may also be used with other providers although if being used in a FIPS context it is the responsibility of the user to ensure that any other providers used are FIPS certified and used appropriately
// https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-fips
implementation group: 'org.bouncycastle', name: 'bcpkix-fips', version: '1.0.7'
Jipher Provider
Jipher JCE is an Oracle-developed Java Cryptography Architecture (JCA) provider that packages a pre-configured and FIPS compliant version of OpenSSL 3.0.
public class JipherProvider {
public static void main(String[] args) {
Security.insertProviderAt(new JipherJCE(), 1);
Provider provider = Security.getProvider("JipherJCE");
//print algorithm supported by provider
System.out.println("-----------Algorithms ------------------");
provider.getServices().stream()
.filter(s -> "Cipher".equals(s.getType()))
.map(Provider.Service::getAlgorithm)
.forEach(name -> System.out.println(name));
}
}
Public Key Infrastructure(PKI)
Public key cryptography and PKI are different.
-
Public key cryptography is also referred to as asymmetric cryptography.
-
PKI is an infrastructure for the secure distribution of public keys that are used in public key cryptography.
A PKI system uses symmetric and asymmetric encryption algorithms and digital certificates(X.509) to provide security for multiple applications and uses. The security that is provided through PKI relies on processes and services that are fundamental. These security services allow for a secure solution to be developed for delivery of information across the Internet. The security services are:
-
Confidentiality —Ensuring that only the intended recipient can read the data
-
Integrity —Ensuring the data has not been altered
-
Authentication —Ensuring that a sender and recipient are who they say they are
-
Non-repudiation — Ensuring an originator cannot refute the validity of a statement or document
FIPS 140-2
FIPS (Federal Information Processing Standard) 140-2 is the benchmark for validating the effectiveness of cryptographic hardware. If a product has a FIPS 140-2 certificate you know that it has been tested and formally validated by the U.S. and Canadian Governments.
The FIPS certification standard defines four increasing, qualitative levels of security:
-
Level 1: Requires production-grade equipment and externally tested algorithms.
-
Level 2: Adds requirements for physical tamper-evidence and role-based authentication. Software implementations must run on an Operating System approved to Common Criteria at EAL2.
-
Level 3: Adds requirements for physical tamper-resistance and identity-based authentication. There must also be physical or logical separation between the interfaces by which “critical security parameters” enter and leave the module. Private keys can only enter or leave in encrypted form.
-
Level 4: This level makes the physical security requirements more stringent, requiring the ability to be tamper-active, erasing the contents of the device if it detects various forms of environmental attack.
Comments
Post a Comment