2012-08-24 61 views
3

我尋找到執行的Java下的當前任務(在Windows上)的最佳方式:隨機生成的「鑰匙」由於用戶看不見的String

由於通過輸入特定的字符串用戶,在程序內部創建隨機的其他字符串/鍵(字母數字),並且用戶不可見。

如果我們輸入相同的字符串,關鍵必須是相同的。

所以基本上,我看到如何做一個隨機字符串,但我想確保該程序的用戶無法找到內部給出的密鑰(我實際上然後使用此密鑰來加密數據,因此我不希望簡單的用戶訪問此密鑰)。

我該如何做到這一點?您能否向我展示一個正確解決方案的代碼示例?

編輯:我要求,具有通過用戶輸入的同一個String相同的密鑰,因爲我需要知道這個生成的密鑰對我的計算機上的下次使用的話,與其他客戶端。

+2

我寧願使用SHA256(SHA-2)而不是MD5。 – Thomas

+1

你能解釋你的問題的背景嗎?然後,我們可以從安全角度爲最佳設計提供建議,然後再介紹如何使用Java實現。 –

+0

@ Duncan:上下文:在用戶端,用戶輸入一個字母數字字符串(前面給出),程序需要生成一個密鑰(由我的程序的用戶解開),然後用於加密一些數據。然後在我的身邊,我需要知道這個密鑰(或生成它)以解密這些數據。 – Arsenic

回答

2

也許是一個鹽醃散列函數?

取用戶輸入,添加一些祕密輸入,並哈希的東西。 (沒有祕密輸入,用戶可以想出如何自己創建這個)。

當然,這個字符串根本不是隨機的。具有這種可重複性的要求排除了隨機性。儘管如此,這些字符串不會有明顯的模式,所以它會看起來是「隨機的」。

+0

我在想同樣的事情 - 它是如何既是隨機又可重複的? –

+0

@ Conor Pender:因爲我需要用另一個程序來檢查某個文件是否由我正在討論的程序加密,而且我沒有看到其他方式來做這件事。 – Arsenic

+0

@ Philo:2個問題:1)如何添加一些用戶不可讀的「祕密輸入」? 2)如何「哈希的東西」。對不起,如果它看起來像你的基本問題.. – Arsenic

0

我不太確定你想實現什麼,但我認爲你可以使用散列來加密你的字符串。

也許這個鏈接可以幫助:How can I generate an MD5 hash?

這是更好,如果你的「鹽」你散列串第一前的字符串。

0

如果您只希望得到相對較少的輸入,您可以使用字符的unicode和隨機數生成一個隨機數,但將所有結果存儲在一張地圖中。這樣,如果已經創建了值,則不會重複生成值,而是使用緩存的值。

+1

除非您必須在地圖不可用的其他機器上再次執行此操作。而當地圖丟失時,你遇到了很大的麻煩。 – Thilo

+0

非常好,但如果整個過程在一臺機器上,它可能是一個有效的解決方案。 –

+0

我明白了你的觀點,但遺憾的是,這必須在不同的機器上運行。但無論如何,謝謝你試圖幫助我。 – Arsenic

2

我真的不知道您的用例是否從安全角度提出建議。但是,要直接解決用戶提供的輸入生成可重複密鑰的問題,可以使用基於密碼的密鑰推導,其中我們將用戶提供的輸入視爲密碼(編輯爲一個完整示例):

import java.security.NoSuchAlgorithmException; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.KeySpec; 

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.SecretKeySpec; 

import sun.security.provider.SecureRandom; 

public class DerivationExample { 

    private static SecretKey makeKeyFromUserInput(String userInput, byte[] salt) 
     throws NoSuchAlgorithmException, InvalidKeySpecException { 

    SecretKeyFactory factory = SecretKeyFactory 
     .getInstance("PBKDF2WithHmacSHA1"); 
    KeySpec keySpec = new PBEKeySpec(userInput.toCharArray(), salt, 1024, 256); 
    byte[] derivedKey = factory.generateSecret(keySpec).getEncoded(); 
    return new SecretKeySpec(derivedKey, "AES"); 
    } 

    public static void main(String[] args) throws Exception { 
    String userInput = "foo"; 

    // PBKDF2 standard recommends at least 64-bit salt 
    // Note: you want to randomly generate this elsewhere and keep it constant 
    byte[] salt = new byte[8]; 
    new SecureRandom().engineNextBytes(salt); 

    SecretKey derivedKey = makeKeyFromUserInput(userInput, salt); 

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    cipher.init(Cipher.ENCRYPT_MODE, derivedKey, new IvParameterSpec(
     new byte[16])); 

    String plaintext = "Hello, World!"; 
    byte[] cipherText = cipher.doFinal(plaintext.getBytes()); 

    // Derive key again to demonstrate it is the same 
    SecretKey derivedKey2 = makeKeyFromUserInput(userInput, salt); 
    cipher.init(Cipher.DECRYPT_MODE, derivedKey2, new IvParameterSpec(
     new byte[16])); 

    byte[] plainText = cipher.doFinal(cipherText); 
    // Prints "Hello, World!" 
    System.out.println(new String(plainText)); 
    } 
} 

如果鹽保持不變,所得到的鍵將是可再現的。在需要產生相同密鑰的任何其他設備之間共享鹽。

注意:您需要安裝不受限制的策略文件(請參閱this page的底部)才能正常工作。

請注意,由「安全」位組成的安全系統在整體上看並不保證安全。我們只看到了一小部分你的要求,因此我們的建議應該採取一撮鹽(沒有雙關語)。要獲得更完整的答案,我們需要了解您嘗試保護的端到端流程。

但是,由於StackOverflow不是設計安全系統的地方,您可能需要在其他地方尋求幫助。

+0

您好,感謝您的幫助和解答。請問您對@Osd提出的代碼有何看法?你認爲你的代碼更「安全」嗎?如果我可能會問,你和他的代碼之間有什麼優勢和劣勢?感謝您的幫助 – Arsenic

+0

@ user1622062 Osd提出的解決方案是一個非常簡單的醃製散列示例。我的例子使用[peer-reviewed方法](ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2_1.pdf)將密碼轉換爲密鑰,涉及哈希函數的醃製和多次迭代。我的方法更安全,應優先使用其他解決方案。 –

+0

2個問題:這個方法返回一個String嗎?我需要用什麼樣的說法來做「鹽」? – Arsenic