Source: CCID
Author: Li Suke
(Reprinted in the preface: a good article I found on the Internet has summarized everything I 've been looking for a few days. I am very grateful to the author: Li Suke was actually looking for materials, the main unsolved problem is how to obtain the privatekey in the keystore file. You can check the jsdk 1.4 API documentation, but I did not find this method after reading it twice from top to bottom: load ().......)
Certificate (also known as Public-Key Certificate) is a digital credential that is obtained by using a signature algorithm to sign certain content (such as a public key) and can be used as a trust relationship intermediary. The Certificate Issuer notifies the certificate user or entity of its public-key and other auxiliary information by issuing the certificate. Certificates are widely used in e-commerce security transactions, and are also known as Ca (CA ).
Application Certificate
The role of a certificate in public key encryption is to ensure that the public key is published in certain trusted organizations. It has important applications in SSL and SET protocols. Figure 1 shows a simple certificate application method:
Figure 1 Certificate Application Method
The application steps of the certificate are as follows:
(1) A sends its own public key (KA) to Ca (Certificate Authority );
(2) ca uses its own private key and a's public key to generate a certificate. The certificate includes the digital signature of CA. The signature object includes the content that needs to be described in the certificate, such as the public key, timestamp, and serial number of A. to simplify this, assume that the certificate contains only three items: the public key of a, the time stamp time1, and the serial number Ida. Then the simple certificate issued by CA to A can be displayed as: certa = ECA [time1, Ida, Ka];
(3) B also sends its own public key PKB to CA;
(4) B. obtain the certificate certb issued by the CA;
(5) A informs B of the certificate certa;
(6) B informs a of the certificate certb.
After a and B obtain the certificate from each other, use the public key obtained from the CA (in the CA's self-signed certificate) to verify whether the certificate of the other party is valid. If yes, the public key of each other is obtained. The public key of the peer can be used to encrypt data or verify the digital signature of the peer.
For convenience, this document does not use the certificate obtained from the ca. Instead, both parties generate a self-signed certificate, that is, A and B in Figure 1 do not pass through the CA, however, the premise is that A and B have the certificate of each other.
The content and meaning of the certificate are shown in table 1 (Here we use the general X. 509 certificate format as an example ).
Table 1 certificate content and meaning
Certificate content |
Meaning |
Version |
Which version of the X.509 Certificate is provided? V1, V2, and V3 are currently available. |
Serial number |
Serial number of the certificate set by the certificate distributor |
Signature Algorithm identifier |
What signature algorithm does the certificate use? |
Issuer name |
The name of the certificate issuer, that is, the name of the organization that signs the certificate. |
Validity Period |
Certificate validity period |
Subject name |
The name of the public key owner or entity signed by the Certificate Authority. It adopts the X.500 Protocol and is unique on the Internet. For example, Cn = Java, ou = Infosec, O = Infosec lab, and c = cn indicates a subject name. |
Detailed definitions of certificates and various protocols related to their applications are not described here, for details, see rfc2450, rfc2510, rfc2511, rfc2527, rfc2528, rfc2559, rfc2560, rfc2585, and rfc2587.
Self-generated visa document
An individual or organization can obtain a certificate from a trusted Certificate distributor, for example, an individual certificate from a http://ca.pku.edu.cn. Here, you can use the security tool keytool of j2sdk to manually generate a self-signed certificate. The self-signed certificate refers to the certificate with the same "Subject name" and "issuer name" in the certificate.
A self-signed certificate is generated below. After j2sdk is installed (j2sdk1.4 is used here), there is a keytool executable program under the bin directory of the j2sdk installation directory. The procedure for using keytool to generate a self-signed certificate is as follows:
Step 1: Use the-genkey Command Option to generate a public-private key pair. Enter keytool-genkey-alias testkeypair-keyalg RSA-keysize 1024-sigalg md5withrsa in the console. Here-alias indicates the alias for using this pair of public/private keys to generate a new keystore entry (the keystore is used to store the management key pair and certificate chain. The default location is in the user's main directory,. you can also specify a path to store hidden files in the name of keystore. keystore file);-keyalg is the algorithm used to generate a public/private key pair. Here it is RSA;-keysize defines the length of the key;-sigalg is the signature algorithm. Select md5withrsa to use RSA signature, then use the MD5 hash algorithm digest. Next, the system will prompt for some input:
Enter the keystore password: abc123
What is your first name and last name?
[Unknown]: Li
What is the name of your organizational unit?
[Unknown]: InfosecLab
What is the name of your organization?
[Unknown]: InfosecLab Group
What is the name of your city or area?
[Unknown]: Beijing
What is the name of your state or province?
[Unknown]: Beijing
What is the two-letter country code of the unit
[Unknown]: CN
CN = Li, OU = InfosecLab, O = InfosecLab Group, L = Beijing, ST = Beijing, C = CN correct?
[No]: y
Enter the master password of <testkeypair> (if it is the same as the keystore password, press Enter):
The second step is to generate a self-signed certificate and enter the following command:
keytool -selfcert -alias testkeypair -dname "CN = Li, OU = InfosecLab, O = InfosecLab
Group, L = Beijing, ST = Beijing, C = CN "
Enter the keystore password: abc123
The third step is to export the self-signed certificate. The certificate generated by the above two steps has been stored in the keystore entry aliased as "testkeypair". If you use its file, you must export the certificate. Enter:
keytool -export -rfc -alias testkeypair -file mycert.crt
Enter the keystore password: abc123
Certificate saved in file <mycert.crt>
In this way, you get a self-signed certificate mycert.crt. Note that the option rfc is to export the certificate to the format defined in RFC1421 and encoded in Base64.
Read certificate
Java provides a rich API for security applications. J2SDK1.4's JSSE (JavaTM Secure Socket Extension) includes the javax.security.certificate package, and provides a method of operating the certificate. The reading operation of the certificate can only use java.security.cert. The following is part of the code to read the contents of the certificate:
import javax.swing. *;
import java.awt. *;
import java.awt.event. *;
import javax.swing.table. *;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.io. *;
public class CARead extends JPanel {
private String CA_Name;
private String CA_ItemData [] [] = new String [9] [2];
private String [] columnNames = {"Certificate Field Tag", "Content"};
public CARead (String CertName) {
CA_Name = CertName;
/ * Three Panels are used to display the contents of the certificate * /
JTabbedPane tabbedPane = new JTabbedPane ();
JPanel panelNormal = new JPanel ();
tabbedPane.addTab ("General Information", panelNormal);
JPanel panelAll = new JPanel ();
panelAll.setLayout (new BorderLayout ());
tabbedPane.addTab ("All information", panelAll);
JPanel panelBase64 = new JPanel ();
panelBase64.setLayout (new BorderLayout ());
tabbedPane.addTab ("Base64 encoding information", panelBase64);
/ * Read the general information of the certificate * /
Read_Normal (panelNormal);
/ * Read the string representation of the certificate file * /
Read_Bin (panelAll);
/ * Read the certificate file in the original Base64 encoding format * /
Read_Raw (panelBase64);
tabbedPane.setSelectedIndex (0);
setLayout (new GridLayout (1, 1));
add (tabbedPane);
}
/ * The following are the defined Read_Normal (), Read_Bin (), Read_Raw () and main ()
Omitted here ... * /
}
The read function for defining certificate information is as follows:
private int Read_Normal (JPanel panel) {
String Field;
try {
CertificateFactory certificate_factory = CertificateFactory.getInstance ("X.509");
FileInputStream file_inputstream = new FileInputStream (CA_Name);
X509Certificate
x509certificate = (X509Certificate) certificate_factory.generateCertificate
(file_inputstream);
Field = x509certificate.getType ();
CA_ItemData [0] [0] = "Type";
CA_ItemData [0] [1] = Field;
Field = Integer.toString (x509certificate.getVersion ());
CA_ItemData [1] [0] = "version";
CA_ItemData [1] [1] = Field;
Field = x509certificate.getSubjectDN (). GetName ();
CA_ItemData [2] [0] = "Title";
CA_ItemData [2] [1] = Field;
/ * The following is similar, omitted here
Field = x509certificate.getNotBefore (). ToString (); Get the start effective date
Field = x509certificate. GetNotAfter (). ToString (); Get the deadline
Field = x509certificate.getSerialNumber (). ToString (16); Get the serial number
Field = x509certificate.getIssuerDN (). GetName (); get the issuer name
Field = x509certificate.getSigAlgName (); Get signature algorithm
Field = x509certificate.getPublicKey (). GetAlgorithm (); Get public key algorithm * /
file_inputstream.close ();
final JTable table = new JTable (CA_ItemData, columnNames);
TableColumn tc = null;
tc = table.getColumnModel (). getColumn (1);
tc.setPreferredWidth (600);
panel.add (table);
} catch (Exception exception) {
exception.printStackTrace ();
return -1;
}
return 0;
}
If you read the certificate as a string, add the following function Read_Bin. The CertificateFactory.generateCertificate () function can extract readable information from the standard encoding of the certificate (defined in RFC1421) The code of the Read_Bin function is as follows:
private int Read_Bin (JPanel panel) {
try {
FileInputStream file_inputstream = new FileInputStream (CA_Name);
DataInputStream data_inputstream = new DataInputStream (file_inputstream);
CertificateFactory certificatefactory = CertificateFactory.getInstance ("X.509");
byte [] bytes = new byte [data_inputstream.available ()];
data_inputstream.readFully (bytes);
ByteArrayInputStream bais = new ByteArrayInputStream (bytes);
JEditorPane Cert_EditorPane;
Cert_EditorPane = new JEditorPane ();
while (bais.available ()> 0) {
X509Certificate
Cert = (X509Certificate) certificatefactory.generateCertificate (bais);
Cert_EditorPane.setText (Cert_EditorPane.getText () + Cert.toString ());
}
Cert_EditorPane.disable ();
JScrollPane edit_scroll = new JScrollPane (Cert_EditorPane);
panel.add (edit_scroll);
file_inputstream.close ();
data_inputstream.close ();
} catch (Exception exception) {
exception.printStackTrace ();
return -1;
}
return 0;
}
If you want to get the encoded information of the original certificate, you can use the following code:
private int Read_Raw (JPanel panel) {
try {
JEditorPane Cert_EditorPane = new JEditorPane ();
String CertText = null;
File inputFile = new File (CA_Name);
FileReader in = new FileReader (inputFile);
char [] buf = new char [2000];
int len = in.read (buf, 0,2000);
for (int i = 1; i <len; i ++)
{
CertText = CertText + buf [i];
}
in.close ();
Cert_EditorPane.setText (CertText);
Cert_EditorPane.disable ();
JScrollPane edit_scroll = new JScrollPane (Cert_EditorPane);
panel.add (edit_scroll);
} catch (Exception exception) {
exception.printStackTrace ();
return -1;
}
return 0;
}
Finally, take a look at the content of the certificate mycert.crt just generated with this small program, and write the file name into main ():
public static void main (String [] args) {
JFrame frame = new JFrame ("Certificate Reader");
frame.addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent e) {System.exit (0);}
});
frame.getContentPane (). add (new CARead ("mycert.crt"), BorderLayout.CENTER);
frame.setSize (700, 425);
frame.setVisible (true);
}
The content of the certificate mycert.crt is displayed as shown in 2. All the information and the display content of Base64 are not listed here.
Figure 2 The content of the certificate mycert.crt is displayed
Now that I have read some of the contents of the certificate, how to use the certificate? We can assume that A and B share a top-secret file F, and B trusts and holds A's certificate, which means that B has A's public key. Then A encrypts the file F through the encryption algorithm (symmetric key algorithm, such as the DES algorithm) known by A and B, and then signs and hashes the encrypted F (such as the MD5 algorithm, the purpose is to ensure the integrity of the file ), And then send F to B. After B receives the file, he first verifies the signature with the public key in A's certificate, and then decrypts it with a commonly known encryption algorithm to get the original file. The digital signature used here can ensure that the file obtained by B is A, and A cannot deny that it does not own file F, because only A has a private key that allows A ’s public key to verify its signature, and at the same time uses the DES algorithm to encrypt, Make documents confidential.
The encryption and decryption functions using the DES algorithm are similar, and the encryption algorithm is not discussed further here. For details, please refer to the JSE part of the J2SDK. The structure of the encryption signature and decryption verification file is shown in Figure 3.
Figure 3 Encryption signature, decryption verification file structure diagram
The desKeyData in the encryption function stores the DES encryption key. If you want to specify it in the program, you can set it to:
static byte [] desKeyData = {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
(byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08};
The encryption function is written as:
public static void crypt (byte [] cipherText, String outFileName) {
try {
DESKeySpec desKeySpec = new DESKeySpec (desKeyData);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance ("DES");
SecretKey secretKey = keyFactory.generateSecret (desKeySpec);
Cipher cdes = Cipher.getInstance ("DES");
cdes.init (Cipher.ENCRYPT_MODE, secretKey);
byte [] ct = cdes.doFinal (cipherText);
try {
FileOutputStream out = new FileOutputStream (outFileName);
out.write (ct);
out.close ();
} catch (IOException e) {
e.printStackTrace ();
}
} catch (Exception e) {
e.printStackTrace ();
}
}
Where ct is the encrypted content, outFileName holds the file name of the encrypted file. Replace cdes.init (Cipher.ENCRYPT_MODE, secretKey) with cdes.init (Cipher.DECRYPT_MODE, secretKey) to decrypt the file.
After the file is encrypted, the file must be signed to ensure that the file sent from A to B cannot be forged. The following is the function to sign with the private key stored in .keystore. The digest algorithm used for signature is MD5. SigText is the input array of the signed content, outFileName is the name of the output file after saving the signature, KeyPassword is the password used to read the Keystore, KeyStorePath is the path to store the .keystore file, and the function code is as follows:
public static void sig (byte [] sigText, String outFileName, String
KeyPassword, String KeyStorePath) {
char [] kpass;
int i;
try {
KeyStore ks = KeyStore.getInstance ("JKS");
FileInputStream ksfis = new FileInputStream (KeyStorePath);
BufferedInputStream ksbufin = new BufferedInputStream (ksfis);
kpass = new char [KeyPassword.length ()];
for (i = 0; i <KeyPassword.length (); i ++)
kpass [i] = KeyPassword.charAt (i);
ks.load (ksbufin, kpass);
PrivateKey priv = (PrivateKey) ks.getKey (KeystoreAlias, kpass);
Signature rsa = Signature.getInstance ("MD5withRSA");
rsa.initSign (priv);
rsa.update (sigText);
byte [] sig = rsa.sign ();
System.out.println ("sig is done");
try {
FileOutputStream out = new FileOutputStream (outFileName);
out.write (sig);
out.close ();
} catch (IOException e) {
e.printStackTrace ();
}
} catch (Exception e) {
e.printStackTrace ();
}
}
To verify the signature, you need to store the signed file, the signed file, and the certificate. Among them, updateData stores the content of the signed file, sawedText stores the obtained signature content, and CertName is the certificate name. The verification signature code is as follows:
public static void veriSig (byte [] updateData, byte [] sigedText) {
try {
CertificateFactory
certificatefactory = CertificateFactory.getInstance ("X.509");
FileInputStream fin = new FileInputStream (CertName);
X509Certificate
certificate = (X509Certificate) certificatefactory.generateCertificate (fin);
PublicKey pub = certificate.getPublicKey ();
Signature rsa = Signature.getInstance ("MD5withRSA");
rsa.initVerify (pub);
rsa.update (updateData);
boolean verifies = rsa.verify (sigedText);
System.out.println ("verified" + verifies);
if (verifies) {
System.out.println ("Verify is done!");
} else {
System.out.println ("verify is not successful");
}
} catch (Exception e) {
e.printStackTrace ();
}
}
You can use keytool to generate two self-signed signature certificates, or go to a CA to apply for two certificates. Using Java to write encryption and verification programs, the above example is just a very simple certificate application. The actual protocol use of certificates (such as SSL) is much more complicated than this.