Ysera
Assistant Engineer
Assistant Engineer
  • UID634
  • Fans0
  • Follows0
  • Posts44
Reads:41589Replies:0

Java security – keys

Created#
More Posted time:May 5, 2017 14:34 PM
Concept
The key is an indispensable part of the encryption algorithm and is vital to the security system. As its name suggests, the key is private and used to open the door to security. There are two key types: symmetric key and asymmetric key. The asymmetric key also contains a public key and a private key.
There is another concept associated with the key: the certificate. The certificate is primarily used to identify the key and the public key is usually transferred in the certificate.
In the Java security system, the key is implemented through the JCE algorithm package. The engine that operates on the key consists of two parts: the key generator and the key factory. The key generator can create a key, and the key factory packages and presents the key as output. For program writing, the creation of the key involves two steps: 1. Produce the key with the key generator; 2. Output the key from the key factory as a key specification or a set of bytecode.
Java implementation
Java encapsulates an interface for the key - Key. The asymmetric key contains PublicKey and PrivateKey, both of which implement this interface. From the output result of the previous "secure provider framework", we can see that different secure providers provide a lot of key generation algorithms, the typical ones being Sun's DSA and RSA and JCE's Diffie-Hellman algorithm.
Key generation and expression
Java provides two generator classes for key generation: KeyPairGenerator and KeyGenerator. The former is used to generate asymmetric keys, and the latter is used to generate symmetric keys. The corresponding key representations are: the KeyFactory class represents asymmetric keys, and the SecretKeyFactory class represents symmetric keys.
Let's look at a DSA example:
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class KeyTest {

    public static void main(String[] args) {
        try {
            generateKeyPair();
            generateKey();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static void generateKeyPair() throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(512);
        KeyPair kp = kpg.generateKeyPair();
        System.out.println(kpg.getProvider());
        System.out.println(kpg.getAlgorithm());
        KeyFactory kf = KeyFactory.getInstance("DSA");
        DSAPrivateKeySpec dsaPKS = kf.getKeySpec(kp.getPrivate(), DSAPrivateKeySpec.class);
        System.out.println("\tDSA param G:" + dsaPKS.getG());
        System.out.println("\tDSA param P:" + dsaPKS.getP());
        System.out.println("\tDSA param Q:" + dsaPKS.getQ());
        System.out.println("\tDSA param X:" + dsaPKS.getX());
    }

    public static void generateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyGenerator kg = KeyGenerator.getInstance("DES");
        SecretKey key = kg.generateKey();
        System.out.println(kg.getProvider());
        System.out.println(kg.getAlgorithm());
        SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
        DESKeySpec desKS = (DESKeySpec) skf.getKeySpec(key, DESKeySpec.class);
        System.out.println("\tDES key bytes size:" + desKS.getKey().length);
    }

}

The code architecture design class diagram for key generation is as follows:



KeyGenerator is similar to KPG, only in that KPG generates KeyPair, while KG generates the SecretKey.
Key management
About certificates
It is difficult to consider where to cover certificates, so I will not discuss it separately. Taking into account that the certificate can verify the legitimacy of the key, this seems like an appropriate place.
The public key should be transferred to the corresponding requestor in the asymmetric key scenario. How can we ensure that this public key is the one I provide to you, instead of a false one provided by someone else? The encryption signature will be required for this transmission. Then the cycle is initiated, and the certificate is introduced – the certificate can ensure that the content is consistent with that of the source, that is to say, the certificate can guarantee that the content sent to the requestor indeed belongs to the content owner.
Not everyone can issue a certificate. The certificate must be issued by a fair entity (CA, certificate authority) and its legitimacy is also verified. The certificate contains three aspects of content:
1. The entity name, that is, the certificate holder.
2. The public key associated with the subject.
3. The digital signature used to verify the certificate information. The certificate is signed by the certificate issuer.
Java has a corresponding Certificate class for certificate-related tasks. Since the certificate is not the focus of our discussion here, and Java itself does not have complete support for certificates, let's digress from certificate content back to the key transmission topic.
KeyStore
The KeyStore class of Java is responsible for key management. KeyStore has a setKeyEntry () method. The general procedure is that KeyStore sets the key as a key entry, and then saves the key as a .keystore file using the store () method. The consumer gets the .keystore file, reads the key entry using the load () method, and then uses it.
If the secret key is asymmetric, write the key entry as follows:
public static void secretKeyStore() throws KeyStoreException, NoSuchAlgorithmException,
                    CertificateException, IOException {
        char[] password = "123456".toCharArray();
        String fileName = System.getProperty("user.home") + File.separator + ".keystore";
        FileInputStream fis = new FileInputStream(fileName);
        KeyStore ks = KeyStore.getInstance("jceks");
        ks.load(fis, password);
        KeyGenerator kg = KeyGenerator.getInstance("DES");
        SecretKey key = kg.generateKey();

        ks.setKeyEntry("myKeyEntry", key, password, null);

        FileOutputStream fos = new FileOutputStream(fileName);
        ks.store(fos, password);
        System.out.println("store key in " + fileName);
    }


Some concepts involved here:
• KeyStore: The place to manage and store the key and certificate. Java key management is built based on the KeyStore.
• Key entry: The KeyStore stores key entries. A key entry either saves an asymmetric key pair or a secret key. If a key pair is saved, a certificate chain may also be saved. The first certificate of the certificate chain contains the public key.
• Alias: Each key can have an alias and can be understood as the name of the key entry.
• Distinguished name: The distinguished name of the entity in the KeyStore is its complete subset of X.500, such as a DN is CN = Yu Jia, OU = ALI, O = ALIBABA, L = HZ, ST = ZJ, C = CN.
• Certificate entry: It contains only one public key certificate. The certificate is stored, instead of the certificate chain.
• JKS, JCEKS, PKCS12: The KeyStore algorithm. The default algorithm in Java is JKS. It can only be used to save the private key. If you want to save the secret key of a symmetric key, you need to use JCEKS, which is the KeyStore ks = KeyStore.getInstance ("jceks"); mentioned in the code above. You can change the default algorithm by modifying keystore.type = JCEKS in the java.security file.
Keytool
Something still seems missing, because the above code cannot be executed if put into the main function. A question also comes up: why is it loaded first for creating a KeyStore?
Look at the source code in the store () method of KeyStore:
public final void store(OutputStream stream, char[] password)
        throws KeyStoreException, IOException, NoSuchAlgorithmException,
            CertificateException
    {
        if (!initialized) {
            throw new KeyStoreException("Uninitialized keystore");
        }
        keyStoreSpi.engineStore(stream, password);
    }


Uninitialized Keystore will throw a KeyStoreException. The initialization action is done in the load() method. That is strange: is the first KeyStore touch'd casually in the system directory?
This introduces the keytool which is a management tool provided by JRE to facilitate the management of KeyStores. The keytool is a command line interface and used to manage the KeyStore. Details about various specific parameters can be found through man keytool or keytool -help.
Here I list how my program initializes a KeyStore:
1. I first generate a key entry with an alias of changed. It adopts the RSA asymmetric algorithm
zunyuanjys-MacBook-Air:~ zunyuan.jy$ keytool -genkey -alias changedi -keyalg RSA
Enter the KeyStore password:
Enter the new password again:
What is your last name and first name?
 [Unknown]: Yu Jia
What is the name of your organization unit?
 [Unknown]: ALI
What is the name of your organization?
 [Unknown]: ALIBABA
What is the name of the city or region you are in?
 [Unknown]: HZ
What is the name of the province/municipality/autonomous region you are in?
 [Unknown]: ZJ
What is the double-letter code of the country/region of the unit?
 [Unknown]: CN
CN=Yu Jia, OU=ALI, O=ALIBABA, L=HZ, ST=ZJ, C=CN. Is it correct?
 [No]: Y

Enter the <changedi> key password
    (If it matches the KeyStore password, press Enter):
Enter the new password again:


2. After entering the DN following the prompts, the KeyStore will be ready. You can check it.
zunyuanjys-MacBook-Air:~ zunyuan.jy$ keytool -list
Enter the KeyStore password:

KeyStore type: JKS
KeyStore provider: SUN

Your KeyStore contains a total of 1 entry.

changedi, 2016-7-7, PrivateKeyEntry,
Certificate fingerprint (SHA1): 76:C8:CE:EA:4C:29:6D:0E:FF:8C:02:BE:F4:F4:55:97:63:1F:C8:26


3. We can see that the store is still of the JKS type and needs to be changed to JCEKS. To do this, perform the following:
zunyuanjys-MacBook-Air:~ zunyuan.jy$ keytool -keypasswd -alias changedi -storetype jceks
Enter the KeyStore password:
Enter the <changedi> key password
New <changedi> key password:
Re-enter the new <changedi> key password:


4. Select the storetype for the list. Because what was just modified is the password, but the core objective is to change the KeyStore type.
zunyuanjys-MacBook-Air:~ zunyuan.jy$ keytool -list -storetype jceks
Enter the KeyStore password:

KeyStore type: JCEKS
KeyStore provider: SunJCE

Your KeyStore contains a total of 1 entry.

changedi, 2016-7-7, PrivateKeyEntry,
Certificate fingerprint (SHA1): 76:C8:CE:EA:4C:29:6D:0E:FF:8C:02:BE:F4:F4:55:97:63:1F:C8:26


5. Run the program and write a secret key for the symmetric key into it as a key entry of this KeyStore. Then list it.
zunyuanjys-MacBook-Air:~ zunyuan.jy$ keytool -list -storetype jceks
Enter the KeyStore password:

KeyStore type: JCEKS
KeyStore provider: SunJCE

Your KeyStore contains a total of 2 entries.

changedi, 2016-7-7, PrivateKeyEntry,
Certificate fingerprint (SHA1): 76:C8:CE:EA:4C:29:6D:0E:FF:8C:02:BE:F4:F4:55:97:63:1F:C8:26
mykeyentry, 2016-7-7, SecretKeyEntry,


In fact, in the above example, you can specify the storetype as JCEKS during the creation of the first key entry. Here I just show how to switch the KeyStore type. In addition, when the RSA private key entry has no certificate specified, a self-signed certificate will also be generated.
Going back to the code, let's look at the details of setKeyEntry:
public final void setKeyEntry(String alias, Key key, char[] password,
                                  Certificate[] chain)
        throws KeyStoreException
    {
        if (!initialized) {
            throw new KeyStoreException("Uninitialized keystore");
        }
        if ((key instanceof PrivateKey) &&
            (chain == null || chain.length == 0)) {
            throw new IllegalArgumentException("Private key must be "
                                               + "accompanied by certificate "
                                               + "chain");
        }
        keyStoreSpi.engineSetKeyEntry(alias, key, password, chain);
    }


It can be seen that a certificate chain is required for the production of asymmetric keys. Otherwise, an exception will be thrown. Taking this situation into account, we generally resort to keytool for non-enterprise-level security scenarios.
Guest