Thứ Sáu, 5 tháng 9, 2014

[Java Security] Phần 5 : Key Management (hệ quản lý key)

Phần 5 : Key Management (hệ quản lý key)
Khi sử dụng public-key crytography, chúng ta cần một cách nào đó để tạo ra public-key và private-key, không chỉ tạo ra mà còn phải có trách nhiệm triển khai một cách bảo mật đến người dùng, cũng như giúp họ nhớ và lưu trữ một cách an toàn nhất. Những hành động như thế được gọi là hệ quản lý key.
Hệ quản lý key bao gồm : tạo ra, triển khai, lưu trữ và kiểm tra. Đây là 4 hoạt động của một hệ quản lý key không chỉ dành riêng cho public-key crytography mà còn secrect-key crytography. Hệ quản lý key là một phần quan trọng và bắt buộc trong hệ thống bảo mật mã hóa.
Chúng ta sẽ học hệ quản lý key của Java Security.
I. Key Representation (biễu diễn key)
KeyRepresentation.png
Mô hình các class và interface được dùng để biễu diễn key
a. Interface Key :
interface Key của gói java.security được sử dụng để biểu diễn key, trong mô hình trên interface key là đại diện cao nhất, có 3 phương thức :
+ getAlgorithm() : trả về tên thuật toán mà key được sử dụng với thuật toán đó.
Ví dụ : DES, DSA, RSA.
+ getEncoded() : trả về key dưới dạng một mảng byte.
+ getFormat() : trả về sự định dạng mà key đã được mã hóa theo định dạng đó.
Ví dụ: RAW, PKCS#8.
b. Interface  PrivateKey , PublicKey, SecretKey :
Đây là 3 interface được kế thừa bởi interface Key .
- PrivateKeyPublicKey thuộc gói java.security, được sử dụng để nhận dạng các private key và public key của thuật toán public-key.
- SecretKey được sử dụng biểu diễn các sercret key trong thuật toán secret-key.
c. Interface  DSAPrivateKey , RSAPrivateKey, DHPrivateKey :
Đây là 3 interface được kế thừa từ interface PrivateKey. DSAPrivateKey và RSAPrivateKey thuộc gói java.security.interfaces và DHPrivateKey thuộc gói javax.crypto.interfaces.  3 interface này được sử dụng để biểu diễn các private key khi sử dụng các thuật toán DSA, RSA và Diffie-Hellman key agreement (thuật toán Diffie-Hellman chúng tôi sẽ trình bày trong những phần sau).
d. Interface DSAPublicKey, RSAPublicKey và DHPublicKey
Đây là 3 inteface kế thừa từ interface PublicKey. DSAPublicKey và RSAPublicKey thuộc java.security.interface và DHPublicKey thuộc javax.crypto.interfaces. 3 interface cung cấp các phương thức để truy cập các giá trị của thuật toán public-key.
e. Class KeyPair :
Class KeyPair thuộc gói java.security được sử dụng để gói gọn cặp public-key và private-key. Class này cung cấp phương thức getPublic()  và getPrivate() để truy cập public-key và private-key.
II. Key Generation (tạo ra key):
Các key đều được tạo ra thông qua các class key generator.
1.Class KeyPairGenerator :
Class KeyPairGenerator là 1 astract class, đối tượng KeyPairGenerator được tạo ra bởi sử dụng phương thức getInstance(),  phương thức này bắt buộc phải có 1 tham số đầu vào là kiểu String để xác định tên thuật toán cần sử dụng.  
Ví dụ:
KeyPairGenerator kpg = KeyPairGenerator.getInstance(“DSA”);
Sau khi đã tạo xong đối tượng KeyPairGenerator bởi sử dụng phương thức getInstance(), tiếp theo chúng ta khởi tạo nó bằng phương thức initialize(), phương thức này nhận 1 tham số đầu vào kiểu integer để chỉ ra số bit dành cho key. Ví dụ : DSA keys phải nằm trong khoảng 512 ->1024 và là bội của 64.
Ví dụ :   kpg.initialize(512);
Sau khi khởi tạo xong đối tượng KeyPairGenerator, chúng ta tạo đối tượng KeyPair bởi sử dụng phương thức genKeyPair().
Ví du:  KeyPair keys = kpg.genKeyPair();
Đây là các bước để tạo ra các key dành cho thuật toán public-key.
Lưu ý : phương thức getInsatnce() và initialize() có nhiều tham số đầu vào khác, ở đây chúng tôi chỉ trình bày cách đơn giản nhất, nếu cần biết nhiều hơn, các bạn tự nghiên cứu thêm.
2. class KeyGenerator :
Class KeyGenerator thuộc gói java.security, tương tự class KeyPairGenerator, được dùng để tạo các key. Nếu class KeyPairGenerator được sử dụng để tạo các key cho thuật toán public-key, thì KeyGenerator được sử dụng để tạo đối tượng SecretKey dành cho thuật toán secret-Key.
Đối tượng KeyGenerator cũng được tạo bởi phương thức getInstance(), phương thức này cũng nhận 1 tham số đầu vào kiểu String, để chỉ ra tên thuật toán,  giá trị bắt buộc phải theo bảng bên dưới :
Ví dụ :
KeyGenerator kg = KeyGenerator. getInstance("DES");
Tiếp theo đối tượng KeyGererator được khởi tạo bởi phương thức init(), phương thức này nhận 1 giá trị đầu vào kiểu integer, để chỉ ra số bit dành cho key.
Ví dụ:   Kg.init(56);
Cuối cùng, sử dụng phương thức generatorKey() để tạo ra đối tượng SecretKey.
Ví dụ :   SecretKey key = kg.generatorKey();
Đây là các bước để tạo ra 1 secretkey dành cho thuật toán secret-key.
Lưu ý : phương thức getInstance() và init(), có thể có nhiều tham số đầu vào khác, ở đây chúng tôi chỉ trình bày các đơn giản nhất, muốn biết nhiều hơn, các bạn tự nghiên cứu thêm.
3. Ví dụ cách tạo key sử dụng class generator :
III. Cách chuyển đổi đối tượng Key thành KeySpec và ngược lại :
Khi sử dụng thuật toán secret-key, bạn muốn nhập mật mã để mật mã này chuyển thành key, hay trong thuật toán RSA, bạn muốn biết giá trị modulus (n) từ public-key thì sao ?
- Trong RSA với java, nếu bạn có đối tượng PublicKey thì bạn không thể nào biết được giá trị n, bắt buộc bạn phải chuyển đối tượng PublicKey này thành RSAPublicKeySpec bạn mới biết được giá trị n.
- Đối với thuật toán secret-key, bạn muốn biến một chuỗi ký tự (mật mã) thành đối tượng SecretKey, bạn phải theo thứ tự (xem lại phần 3) :
+ Đưa chuỗi ký tự đó vào đối tượng KeySpec với thuật toán tương ứng (ví dụ : DESKeySpec, DESedeKeySpec,…).
+ Tạo đối tượng SecretKeyFactory.
+ Tạo đối tượng SecretKey thông qua SecretKeyFactory và KeySpec.
Ba class chính được sử dụng để chuyển đổi là:
+ java.security.KeyFactory
+ javax.crypto.SecretKeyFactory
+ javax.crypto.spec.KeySpec.
1. interface KeySpec : chỉ ra các thành phần mà tạo thành 1 key.
Các class được kế thừa từ KeySpec:
+ java.security.spec.DSAPrivateKeySpec : nhận các giá trị đầu vào (g,p,q và x) của một private-key  thuật  toán DSA.
+ java.security.spec.DSAPublicKepSpec : nhận các giá trị đầu vào (g,p,q và y) của một public-key thuật toán DSA.
+ java.security.spec.EncodedKeySpec : nhận các giá trị đầu vào public-key và private-key dưới dạng một mảng byte được encode.
+ java.security.spec.RSAPublicKeySpec : nhận các giá trị đầu vào (hệ số, số mũ) của public-key thuật toán RSA.
+ java.security.spec.RSAPrivateKeySpec : nhận các giá trị đầu vào (hệ số, số mũ) của public-key thuật toán RSA.
+ javax.crypto.spec.DESedeKeySpec :  nhận các giá trị đầu vào dưới dạng mảng byte của thuật toán DESede.
+ javax.crypto.spec.DESKeySpec : nhận các giá trị đầu vào dưới mảng byte của thuật toán DES.
+ javax.crypto.spec.DHPrivateKeySpec :  nhận các giá trị đầu vào (g,p,x) của private-key thuật toán Diffie-Hellman.
+ javax.crypto.spec.DHPublicKeySpec :  nhận các giá trị đầu vào (g,p,y) của public-key thuật toán Diffie-Hellman.
+ javax.crypto.spec.PBEKeySpec :  nhận các giá trị đầu vào dưới dạng mảng char của thuật toán mã hóa key dựa trên password.
+ javax.crypto.spec.SecretKeySpec :  nhận các giá trị đầu vào dưới dạng một mảng byte và chỉ ra thuật toán Secret-key.
2. class KeyFactory :
KeyFactory được xem là trung gian chuyển đổi qua lại giữa các đối tượng KeySpec và PublicKey và PrivateKey. Đối tượng KeyFactory được tạo ra bởi phương thức getInstance(), phương thức này nhận 1 tham số đầu vào bắt buộc là kiểu string tên của thuật toán mã hóa public-key, chỉ có 3 giá trị tương ứng 3 thuật toán được hổ trợ trong java:
Ví dụ : KeyFactory keyFactory = KeyFactory.getInstance("DSA");
Các phương thức của class KeyFactory:
+ getKeySpec(Key key, class KeySpec) : tạo ra đối tượng KeySpec tương ứng với key được chỉ ra.
+ generatePrivate(KeySpec keySpec) : tạo ra đối tượng PrivateKey từ đối tượng keySpec.
+ generatePublic(KeySpec keySpec) : tạo ra đối tượng PublicKey từ đối tượng keySpec.
Ví dụ : chương trình chuyển đổi RSAPrivateKey và RSAPublicKey thành RSAPrivateKeySpec và RSAPublicKeySpec.
3. class SecretKeyFactory :
SecretKeyFactory thuộc gói javax.crypto là trung gian cho phép chuyển đổi qua lại giữa các đối tượng KeySpecSecretKey. Đối tượng SecretKeyFactory được tạo ra bởi phương thức getInstance(), phương thức này nhận 1 giá trị đầu vào bắt buộc kiểu String, là tên thuật toán dành cho secret-key, các giá trị này là :
Ví dụ :
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
Các phương thức của class SecretKeyFactory:
+ generateSecre(KeySpec keySpec) : tạo ra đối tượng SecretKey từ đối tượng KeySpec.
+ getKeySpec(SecretKey key, KeySpec keySpec) : tạo ra đối tượng KeySpec từ đối tượng SecretKey.
III. Key Agreement (sự trao đổi key giữa các hệ thống khác nhau) :
Key agreement là một qui trình mà nhiều bên tham gia sẽ tạo thành một hiệp định về các Key được sử dụng trong quá trình mã hóa dữ liệu trao đổi với các bên. Dễ hiểu hơn, Key Agreement là quá trình trao đổi và triển khai Key từ bên A đến bên B và ngược lại, sao cho an toàn nhất.
Trong hệ thống public-key, key agreement khá đơn giản. Bên A chỉ cần cung cấp cho bên B, bên C, bên D,…, public key do bên A cung cấp. Public key này được triển khai dưới dạng digital certificate (digital certificate, chúng tôi sẽ trình bày trong phần sau). Digital certificate này được sử dụng bởi người nhận để xác nhận public-key này có đúng là bên A đã cung cấp hay không ? Nếu đúng, bên B, bên C,…, chỉ cần sử dụng public-key này để mã hóa dữ liệu rồi chuyển đến bên A. Bên A, dùng private-key của mình để giải mã dữ liệu đã nhận được. Đến đây, bạn sẽ giải đáp thắc mắc  “hệ thống public-key rất tuyệt vời, nhưng tại sao trong thực tế vẫn còn nhiều hệ thống secret-key ? “ , từ trường hợp trên bạn thấy rất rõ, bên B, bên C,.., gởi bên A dữ liệu được mã hóa bởi public-key, vậy bên A muốn gởi dữ liệu cho bên B, bên C,… được không ? Câu trả lời là "không được", bên B, bên C,.. cũng phải tạo ra hệ thống public-key và gởi public-key cho bên A.  Trong những trường hợp như thế này, người ta vẫn thích hệ thống secret-key hơn.
Trong hệ thống secret-key, key agreement rất phức tạp. Vì chỉ có duy nhất 1 secret-key, nếu không tính toán kỹ lưỡng sẽ  làm lộ tất cả thông tin. Người ta sử dụng rất nhiều biện pháp như : key chỉ tồn tại trong 1 khoảng thời gian nhất định, hay key chỉ sử dụng cho không quá số lượng người dùng,..nhưng biện pháp nào cũng có khẽ hở cả, từ đó các giao thức key agreement ra đời.
Giao thức Key agreement hiệu quả và phổ biến nhất do Whitfield DiffieMartin Hellman phát triển, đó là “Diffie-Hellman key agreement protocol”.  
1. mô hình làm việc của Diffie-Hellman key agreement:



  
lưu ý :
+ Session key : là 1 secret- key , chỉ tồn tại trong 1 phiên làm việc thôi, đối với những phiên làm việc khác nhau sẽ có giá trị K khác nhau.
+ Xa  được xem là private-key và Yb  được xem là public-key của a.
+ Xb được xem là private-key và Ya được xem là public-key của b.
2. Key Agreement trong Java:
Java hổ trợ key agreement qua class KeyAgreement trong gói javax.crypto. Phương thức getInstance() được sử dụng để tạo đối tượng KeyAgreement, phương thức này bắt buộc 1 tham số đầu vào kiểu String là tên thuật toán Key Agreement, các giá trị dành cho kiểu String này là :
Ví dụ :
KeyAgreement ka1 = KeyAgreement.getInstance(“DH”);
KeyAgreement ka2 = KeyAgreement.getInstance(“DH”);
(lưu ý : 1 đối tượng KeyAgreement chỉ đại diện cho 1 bên, nếu có 2 bên thì phải có 2 đối tượng KeyAgreement )
Sau khi hoàn thành tạo đối tượng KeyAgreement , chúng ta phải khởi tạo đối tượng KeyAgreement này qua phương thức init(), tham số đầu vào của phương thức này là 1 private key (là giá trị X trong Diffie-Hellman)
Ví dụ :
ka1.init(private-key1);
Ka2.init(private-key2);
Bước tiếp theo là trao đổi public-key (đó là Y) giữa 2 bên, bằng phương thức doPhase(). Phương thức này nhận tham số đầu vào là 1 public-key và 1 giá trị kiểu boolean, giá trị kiểu boolean này được sử dụng để chỉ ra đây có phải là giai đoạn cuối cùng của đối tượng KeyAgreement này không.
Ví dụ :
ka1.doPhase(public-key2, true);
Ka2.doPhase(public-key1, true);
Kế tiếp là tạo ra 1 secret-key (Session Key K) để mã hóa dữ liệu trao đổi giữa 2 bên, bằng phương thức generateSecret() , phương thức này nhận tham số đầu vào là tên thuật toán secret-key.   
Ví dụ :
SecretKey key1 = ka1.generateSecret(“DES”);
SecretKey key2 = ka2.generateSecret(“DES”);
3. Ví dụ Key Agreement bằng java :


3 nhận xét: