Thursday, November 20, 2014

Mã hóa dữ liệu khi lưu trữ trong ứng dụng Java + SQL Server

Thông thường dữ liệu các nhân của người dùng khi lưu trữ vào csdl chúng ta nên che đi những dữ liệu nhạy cảm, trong ví dụ sau đây chúng ta cùng làm một demo nhỏ để che đi dữ liệu email và ngày sinh của người dùng (chỉ có ứng dụng của chúng ta mới giải mã được)

Tạo bảng để lưu được thông tin sau:
Order.    Name        Type
1.    Username    Text
2.    Password    Text
3.    Fullname    Text
4.    Address     Text
5.    Email       Text
6.    Birthdate   Date

Yêu cầu

Thiết kế form thêm thông tin người dùng vào bảng trên với các yêu cầu sau:
    1.    Mã hóa Password bằng giải thuật MD5
    2.    Mã hóa email và birthdate bằng giải thật mã hóa 02 chiều

Thiết kế form hiển thị ds người dùng thể hiện các cột: Username, Fullname và Address
Thiết kế form tìm người dùng dựa vào Username, kết quả hiển thị chi tiết người dùng gồm thông tin
       Username
    •    Fullname
    •    Address
    •    Email và Birthdate đã được giải mã

Giao diên thêm và tìm thông tin

image Dữ liệu đã mã hóa

image Dữ liệu được giải mã (nhấn nút find)

image

Bước 1: Tạo CSDL tên data và bảng nguoidung

1 SET ANSI_NULLS ON
2 GO
3
4 SET QUOTED_IDENTIFIER ON
5 GO
6
7 SET ANSI_PADDING ON
8 GO
9
10 CREATE TABLE [dbo].[users](
11 [username] [varchar](50) NULL,
12 [password] [varchar](100) NULL,
13 [fullname] [varchar](100) NULL,
14 [address] [varchar](250) NULL,
15 [email] [varbinary](max) NULL,
16 [birthdate] [varbinary](max) NULL
17 ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
18
19 GO
20
21 SET ANSI_PADDING OFF
22 GO

Bước 2: Tạo cập khóa cho ứng dụng và lưu trữ lại để sử dụng (file)


1 class KeyGen {
2 public static void main(String[] args) {
3 try {
4 if (!new File("src/lib/pri.key").exists()) {
5 KeyPairGenerator key = KeyPairGenerator.getInstance("RSA");
6 key.initialize(512);
7 KeyPair keys = key.genKeyPair();
8 // Tạo cặp khóa
9 PrivateKey privateKey = keys.getPrivate();
10 PublicKey publicKey = keys.getPublic();
11 // Lưu thông tin khóa để tái sử dụng, khóa công khai để giải mã
12 X509EncodedKeySpec x509EncodedKeySpec =
13 new X509EncodedKeySpec(publicKey.getEncoded());
14 FileOutputStream fos = new FileOutputStream("src/lib/pub.key");
15 fos.write(x509EncodedKeySpec.getEncoded());
16 fos.close();
17 // khóa mật để mã hóa
18 PKCS8EncodedKeySpec pkcs8EncodedKeySpec =
19 new PKCS8EncodedKeySpec(privateKey.getEncoded());
20 fos = new FileOutputStream("src/lib/pri.key");
21 fos.write(pkcs8EncodedKeySpec.getEncoded());
22 fos.close();
23 } else {
24 System.out.println("Khoa da co");
25 }
26 } catch (IOException ex) {
27 Logger.getLogger(KeyGen.class.getName()).log(Level.SEVERE, null, ex);
28 } catch (NoSuchAlgorithmException ex) {
29 Logger.getLogger(KeyGen.class.getName()).log(Level.SEVERE, null, ex);
30 }
31 }
32 }






Tới đây chúng ta đã có được cặp khóa để có thể mã hóa và giải mã những dữ liệu cần thiết.


Bước 3: Xây dựng lớp Encode để phục hồi khóa từ tập tin và tạo phương thức mã hóa, giải mã.



1 public class Encode {
2 private PrivateKey priKey;
3 private PublicKey pubKey;
4 public Encode() {
5 getKeys();
6 }
7 private void getKeys() {
8 try {
9 File pubKeyFile = new File("src/lib/pub.key");
10 File privKeyFile = new File("src/lib/pri.key");;
11 // đọc dữ liệu từ file và khởi tọa lại khóa công khai
12 DataInputStream dis = new DataInputStream(new FileInputStream(pubKeyFile));
13 byte[] pubKeyBytes = new byte[(int) pubKeyFile.length()];
14 dis.readFully(pubKeyBytes);
15 dis.close();
16
17 // đọc dữ liệu từ file và khởi tọa lại khóa mật
18 dis = new DataInputStream(new FileInputStream(privKeyFile));
19 byte[] privKeyBytes = new byte[(int) privKeyFile.length()];
20 dis.read(privKeyBytes);
21 dis.close();
22 //
23 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
24 // Tạo khóa công khai
25 X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubKeyBytes);
26 pubKey = (RSAPublicKey) keyFactory.generatePublic(pubSpec);
27 // tạo khóa mật
28 PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privKeyBytes);
29 priKey = (RSAPrivateKey) keyFactory.generatePrivate(privSpec);
30 } catch (Exception ex) {
31 System.out.println("ERR: " + ex.toString());
32 }
33 }
34 // hàm mã hóa
35 public byte[] TwowayEncrypt(byte[] data) {
36 try {
37 Cipher c = Cipher.getInstance("RSA");
38 c.init(Cipher.ENCRYPT_MODE, priKey);
39 byte[] rs = c.doFinal(data);
40 return rs;
41 } catch (Exception ex) {
42 System.out.println("Err: " + ex.toString());
43 }
44 return null;
45 }
46 // hàm giải mã
47 public byte[] TwowayDecrypt(byte[] data) {
48 try {
49 Cipher c = Cipher.getInstance("RSA");
50 c.init(Cipher.DECRYPT_MODE, pubKey);
51 byte[] rs = c.doFinal(data);
52 return rs;
53 } catch (Exception ex) {
54 System.out.println("Err: " + ex.toString());
55 }
56 return null;
57 }
58 // dùng cho mã hóa mật khẩu
59 public byte[] OnewayEncrypt(byte[] data){
60 try {
61 MessageDigest dig = MessageDigest.getInstance("MD5");
62 return dig.digest(data);
63 } catch (Exception ex) {
64 System.out.println("ERR: "+ ex.toString());
65 }
66 return null;
67 }
68 }


Bước 4: Tích hợp lên giao diện


Xử lý sự kiện Click nút Add new


1 private void btnAddActionPerformed(java.awt.event.ActionEvent evt) {
2 try {
3 Connection conn = DriverManager.getConnection("jdbc:sqlserver://ntdan;databasename=data;", "sa", "sa");
4 PreparedStatement comm = conn.prepareStatement("Insert into users values(?,?,?,?,?,?)");
5 comm.setString(1, txtUser.getText());
6
7 byte[] ba1 = Charset.forName("UTF-8").encode(CharBuffer.wrap(txtPass.getPassword())).array();
8
9 comm.setString(2, new String(encode.OnewayEncrypt(ba1), "UTF-8"));
10 comm.setString(3, txtFull.getText());
11 comm.setString(4, txtAdd.getText());
12
13 comm.setBytes(5,encode.TwowayEncrypt(txtEmail.getText().getBytes("UTF-8")));
14 comm.setBytes(6, encode.TwowayEncrypt(txtBirth.getText().getBytes("UTF-8")));
15
16 comm.executeUpdate();
17 } catch (Exception ex) {
18 System.out.println("ERR: " + ex.toString());
19 }
20 }

Xử lý sự kiện Click nút Find


1 private void btnFindActionPerformed(java.awt.event.ActionEvent evt) {
2 try {
3 Connection conn = DriverManager.getConnection("jdbc:sqlserver://ntdan;databasename=data;", "sa", "sa");
4 PreparedStatement comm = conn.prepareStatement("Select * from Users where username=?");
5 comm.setString(1, txtUser.getText());
6 ResultSet rs = comm.executeQuery();
7 String found="";
8 if(rs.next())
9 {
10 found = "User: ";
11 found += rs.getString(1);
12 found += "\nFullname: "+rs.getString(3);
13 found += "\nAddress: "+rs.getString(4);
14 found += "\nEmail: "+ new String(encode.TwowayDecrypt(rs.getBytes(5)),"UTF-8");
15 found += "\nBirthDate: "+ new String(encode.TwowayDecrypt(rs.getBytes(6)),"UTF-8");
16 }
17
18 JOptionPane.showMessageDialog(this, found);
19 } catch (Exception ex) {
20 System.out.println("Err: "+ ex.toString());
21 }
22 }



OK, như vậy là cơ bản chúng ta đã một phần nào đó che đi dữ liệu email và ngày sinh khi lưu vào SQL Server.


 


Đây là một ví dụ nhỏ hi vọng sẽ giúp chúng ta có cái nhìn rất cơ bản về việc bảo vệ dữ liệu riêng tư cho ứng dụng.

No comments:

Post a Comment

Translate