23

Tôi đang cố gắng sử dụng Curve25519 trong ứng dụng Android của mình để mã hóa/giải mã khóa mã hóa AES cục bộ. Tôi không cần bất kỳ trao đổi chính, thỏa thuận chính hoặc ký. Tại sao tôi cần phải sử dụng đường cong cụ thể đó? Bởi vì tôi cần có khả năng tự cung cấp khóa riêng và có thể tính toán khóa công khai phù hợp. Vì vậy, theo như tôi nhận được, chỉ Curve25519 làm điều này. Hãy sửa tôi nếu tôi sai.Sử dụng ECC Curve25519 để mã hóa/giải mã dữ liệu trong Java

Tất cả triển khai Curve25519 chỉ thực hiện tạo khóa, trao đổi khóa và ký/xác minh.

Có thể thực hiện mã hóa/giải mã dữ liệu sau khi tôi nhận Curve25519 khóa công khai/riêng tư hoặc có thể đề xuất bất kỳ đường cong thay thế nào phù hợp với tiêu chí của tôi không?

Sửa

Vậy tại sao tôi cần điều này? Tôi sẽ giải thích kỹ hơn. Ứng dụng của tôi đang thực hiện mã hóa tệp cục bộ, đặc biệt là ảnh. Mục tiêu của tôi là có thể cho người dùng chụp ảnh mà không cần nhập mật khẩu và sau đó nhập mật khẩu để xem chúng. Đối với điều này tôi cần để có thể tạo cặp khóa công khai/riêng tư từ mật khẩu và có thể tạo lại khi đang bay cùng một cặp khóa bất cứ khi nào mật khẩu được cung cấp. Vì vậy, vào lần chạy đầu tiên tôi tạo ra cặp khóa ECC từ mật khẩu và lưu trữ khóa công khai trên thiết bị. Khi người dùng muốn chụp ảnh mã hóa ứng dụng ảnh mới bằng khóa AES 256 bit ngẫu nhiên và sau đó mã hóa khóa đó bằng khóa công cộng được lưu trữ. Khi người dùng muốn xem ảnh, anh/cô ấy cung cấp mật khẩu chính xác, tôi lấy cùng một cặp khóa ECC và giải mã khóa AES bằng khóa riêng của tôi và sau đó tôi có thể giải mã ảnh bằng AES 256.

Vì vậy, theo như tôi nhận được Curve25519 cho tôi khả năng này hoặc có bất kỳ lựa chọn thay thế nào khác. Các ví dụ mã trong Java được hoan nghênh!

+0

Bạn có thể sử dụng [này] (http://stackoverflow.com/a/30014831/1816580) để nhanh chóng ECIES. –

+0

Thực hiện trao đổi khóa với khóa công khai của người nhận và sử dụng khóa chia sẻ để mã hóa bằng mã hóa đối xứng như XSalsa20Poly1305 hoặc AES-GCM. – CodesInChaos

+0

Có lẽ bạn không hiểu điều đó. Tôi không có bất kỳ bên nhận nào, tất cả mã hóa và giải mã đều là cục bộ. –

Trả lời

2

Chìa khóa để mã hóa tệp trên thiết bị Android là không bao giờ lưu khóa. Với điều này, bạn đã thêm ràng buộc mã hóa hình ảnh không nên yêu cầu mật khẩu. Cuối cùng, vì mã hóa bất đối xứng chậm, bạn sẽ cần AES để thực hiện việc nâng hạng nặng.

Điều này làm việc với RSA hoặc bất kỳ thuật toán bất đối xứng nào khác.

Initial Run

  1. On chạy đầu tiên, tạo ra một cặp khóa và yêu cầu người dùng nhập mật khẩu.
  2. Lưu trữ khóa công khai rõ ràng. Mã hóa khóa riêng bằng khóa AES được tạo từ mật khẩu.

Encryption

  1. Tạo một khoá AES khác nhau cho mỗi bức ảnh và mã hóa hình ảnh với nó. Mã hóa khóa AES bằng khóa công khai và lưu trữ cùng với hình ảnh.

Decryption

  1. Có người dùng nhập mật khẩu. Tạo khóa AES đầu tiên từ đó. Sử dụng nó để giải mã khóa riêng. Giải mã khóa AES cho hình ảnh này bằng khóa riêng. Sử dụng phím AES để giải mã tập tin và hiển thị nó.

(Chúng tôi thực sự có 4 khóa.Chúng tôi cần cặp khóa để cho phép chúng tôi mã hóa mà không cần mật khẩu. Chúng tôi cần khóa AES đầu tiên để lưu khóa riêng tư một cách an toàn. Chúng tôi cần khóa AES thứ hai và thay đổi để mã hóa tệp.)

Tôi nghĩ điều này sẽ an toàn, ngoại trừ các cuộc tấn công như ghi nhật ký khóa. Mã Java nên rất đơn giản. Hy vọng điều này là rõ ràng.

============================================== ========================

Ví dụ hoàn chỉnh Sử dụng AES và RSA. Đối với Curve, chỉ chuyển mã RSA, mặc dù nó không được hỗ trợ ra khỏi hộp, vì vậy bạn sẽ cần một thư viện bên ngoài. Ngoài ra, vì lợi ích của thời gian và ngắn gọn, mã này kém an toàn hơn mức cần thiết. Ví dụ, tôi đã sử dụng ECB chứ không phải CBC.

package il.co.falk; 

import javax.crypto.*; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 
import java.security.*; 
import java.security.spec.KeySpec; 
import java.security.spec.PKCS8EncodedKeySpec; 

public class SecureFile { 
private PublicKey publicKey; 
private byte[] privateKeyArray; 
private byte[] salt = {1,2,3,4,5,6,7,8}; 


public static void main(String[] args) { 
    String password = "PASSWORD"; 
    SecureFile secureFile = new SecureFile(password); 
    secureFile.test(); 
} 


public void test() { 
    String password = "PASSWORD"; 
    String imageFile = "348756348975634897562398479623896"; 

    ImageAndKey imageAndKey = encryptImage(imageFile.getBytes()); 
    byte[] decryptedImage = decryptImage(imageAndKey, password); 

    System.out.println(new String(imageFile)); 
    System.out.println(new String(decryptedImage)); 
} 

public SecureFile(String password) { 
    try { 
     generateRSAKeys(password); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 



public ImageAndKey encryptImage(byte[] imageBytes) { 
    try { 
     byte[] secretKeyBytes = generateAESKey(); 
     byte[] encryptedFile = aesEncrypt(imageBytes, secretKeyBytes); 
     byte[] encryptedKey = rsaEncrypt(secretKeyBytes); 

     return new ImageAndKey(encryptedFile, encryptedKey); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     return null; 
    } 

} 

public byte[] decryptImage(ImageAndKey imageAndKey, String password) { 
    try { 
     byte[] secretKeyBytes = generateAESKey(password); 
     byte[] decryptedPrivateKey = aesDecrypt(privateKeyArray, secretKeyBytes); 
     byte[] decryptedKey = rsaDecrypt(imageAndKey.aesKey, decryptedPrivateKey); 

     SecretKey secretKey = new SecretKeySpec(decryptedKey, "AES"); 
     secretKeyBytes = secretKey.getEncoded(); 

     byte[] decryptedBytes = aesDecrypt(imageAndKey.imageBytes, secretKeyBytes); 

     return decryptedBytes; 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 



// RSA 
private void generateRSAKeys(String password) throws Exception { 
    final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 
    keyGen.initialize(512); // TODO: make this 2048 at least 
    final KeyPair keyPair = keyGen.generateKeyPair(); 
    publicKey = keyPair.getPublic(); 
    PrivateKey privateKey = keyPair.getPrivate(); 

    byte[] secretKeyBytes = generateAESKey(password); 
    byte[] privateKeyBytes = privateKey.getEncoded(); 
    privateKeyArray = aesEncrypt(privateKeyBytes, secretKeyBytes); 
} 

public byte[] rsaEncrypt(byte[] plainText) throws Exception { 
    final Cipher cipher = Cipher.getInstance("RSA"); 
    cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
    byte[] cipherText = cipher.doFinal(plainText); 
    return cipherText; 
} 

public byte[] rsaDecrypt(byte[] cipherText, byte[] decryptedPrivateKeyArray) throws Exception { 
    PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKeyArray)); 

    final Cipher cipher = Cipher.getInstance("RSA"); 
    cipher.init(Cipher.DECRYPT_MODE, privateKey); 
    byte[] plainText = cipher.doFinal(cipherText); 
    return plainText; 
} 

// AES 
private byte[] aesEncrypt(byte[] plainText, byte[] secretKeyBytes) throws Exception { 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(secretKeyBytes)); 
    byte[] cipherText = cipher.doFinal(plainText); 
    return cipherText; 
} 

public byte[] aesDecrypt(byte[] cipherText, byte[] secretKeyBytes) throws Exception { 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, getSecretKey(secretKeyBytes)); 
    byte[] plainText = cipher.doFinal(cipherText); 
    return plainText; 
} 

private byte[] generateAESKey() throws Exception { 
    KeyGenerator keyGen = KeyGenerator.getInstance("AES"); 
    keyGen.init(256); 
    SecretKey secretKey = keyGen.generateKey(); 
    return secretKey.getEncoded(); 
} 

private byte[] generateAESKey(String password) throws Exception { 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256); 
    SecretKey tmp = factory.generateSecret(spec); 
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES"); 
    return secret.getEncoded(); 
} 

private SecretKey getSecretKey(byte[] secretKeyBytes) throws Exception { 
    SecretKey secretKey = new SecretKeySpec(secretKeyBytes, "AES"); 
    return secretKey; 
} 



// Classes 
class ImageAndKey { 
    public byte[] imageBytes; 
    public byte[] aesKey; 

    public ImageAndKey(byte[] imageBytes, byte[] aesKey) { 
     this.imageBytes = imageBytes; 
     this.aesKey = aesKey; 
    } 
} 

}

+0

Những gì bạn mô tả là rõ ràng trước và tôi sẽ theo cách đó. Những gì tôi cần là đoạn mã, chỉ là một ví dụ về tạo khóa và mã hóa/giải mã dữ liệu bằng cách sử dụng Curve25519 ECC. –

+0

Bất kỳ lý do nào nó phải là đường cong? Nó không phải là một phần của tiêu chuẩn Android và AES256 và RSA. –

Các vấn đề liên quan