2017-08-26 77 views
3

我在我的程序中使用了PBKDF2密碼哈希技術。到我指的示例程序是在C. 該程序代碼段如下:Java代碼的C實現中的輸出差異

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <getopt.h> 
#include <openssl/evp.h> 
#include <openssl/rand.h> 
#include "base64.h" 

#define KEY_LENGTH  24 
#define SEPARATOR  "$" 
#define SALTLEN 12 

#define USAGE() fprintf(stderr, "Usage: %s [-i iterations] [-p password]\n", progname) 

int main(int argc, char **argv) 
{ 
    int iterations = 901, rc, blen; 
    unsigned char saltbytes[SALTLEN]; 
    char *salt, *b64; 
    unsigned char key[128]; 
    char *pw1, *pw2, *password; 
    char *progname = argv[0]; 
    int c; 
    int prompt; 

    prompt = 1; 

    while ((c = getopt(argc, argv, "i:p:")) != EOF) { 
     switch (c) { 
      case 'i': 
       iterations = atoi(optarg); 
       break; 
      case 'p': 
       pw1 = strdup(optarg); 
       pw2 = strdup(optarg); 
       prompt = 0; 
       break; 
      default: 
       exit(USAGE()); 
     } 
    } 

    argc -= optind - 1; 
    argv += optind - 1; 

    if (argc != 1) { 
     exit(USAGE()); 
    } 

    if (prompt) { 
     pw1 = strdup(getpass("Enter password: ")); 
     pw2 = getpass("Re-enter same password: "); 
    } 

    if (strcmp(pw1, pw2) != 0) { 
     fprintf(stderr, "Passwords don't match!\n"); 
     return (1); 
    } 

    password = pw1; 

    rc = RAND_bytes(saltbytes, SALTLEN); 
    if (rc == 0) { 
     fprintf(stderr, "Cannot get random bytes for salt!\n"); 
     return 2; 
    } 

    base64_encode(saltbytes, SALTLEN, &salt); 

#ifdef RAW_SALT 
    PKCS5_PBKDF2_HMAC(password, strlen(password), 
     (unsigned char *)saltbytes, SALTLEN, 
     iterations, 
     EVP_sha256(), KEY_LENGTH, key); 
#else 
    int saltlen; 
    saltlen = strlen(salt); 

    PKCS5_PBKDF2_HMAC(password, strlen(password), 
     (unsigned char *)salt, saltlen, 
     iterations, 
     EVP_sha256(), KEY_LENGTH, key); 
#endif 


    blen = base64_encode(key, KEY_LENGTH, &b64); 
    if (blen > 0) { 
     printf("PBKDF2$%s$%d$%s$%s\n", 
      "sha256", 
      iterations, 
      salt, 
      b64); 

     free(b64); 
    } 

    free(password); 
    return 0; 
} 

與C程序的輸出如下所示: PBKDF2 $ SHA256 $ 901 $ QLtznh6yjEs4a4Fl $ uzp3QAEpFZsqBvCssnL1eXZFxCiKzV7P

我試圖複製相同的在Java中,這是如下:

public class NewPBKDF2 { 

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     String originalPassword = "A3E9907E59A6379DB6A9C2657D242A64886D5B21E3586B3D4C2B4E6329570A10"; 
     String generatedSecuredPasswordHash = generateStorngPasswordHash(originalPassword); 
     System.out.println(generatedSecuredPasswordHash); 
    } 

    private static String generateStorngPasswordHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException { 
     int iterations = 901; 
     char[] chars = password.toCharArray(); 
     byte[] salt = getSalt(); 
     String salt1 = Base64.getEncoder().encodeToString(salt); 
     int length = 24; 




     PBEKeySpec spec = new PBEKeySpec(chars, salt, iterations, length * 8); 
     SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); 
     byte[] hash = skf.generateSecret(spec).getEncoded(); 
     String hash1 = bytesToHex(hash); 

     try { 
      hash1 = Base64.getEncoder().encodeToString(hash1.getBytes("utf-8")); 
     } catch (UnsupportedEncodingException ex) { 
      Logger.getLogger(NewPBKDF2.class.getName()).log(Level.SEVERE, null, ex); 
     } 


     return "PBKDF2$sha256$"+ iterations +"$"+salt1+"$"+hash1; 
    } 

    private static byte[] getSalt() throws NoSuchAlgorithmException { 
     SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 

     byte[] salt = new byte[12]; 


     sr.nextBytes(salt); 
     return salt; 
    } 

    static char[] hexArray = "ABCDEF".toCharArray(); 
    public static String bytesToHex(byte[] bytes) { 
     char[] hexChars = new char[bytes.length * 2]; 
     for (int j = 0; j < bytes.length; j++) { 
      int v = bytes[j] & 0xFF; 
      hexChars[j * 2] = hexArray[v >>> 4]; 
      hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
     } 
     return new String(hexChars); 
    } 

    public static byte[] hexStringToByteArray(String s) { 
     int len = s.length(); 
     byte[] data = new byte[len/2]; 
     for (int i = 0; i < len; i += 2) { 
      data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) 
        + Character.digit(s.charAt(i+1), 16)); 
     } 
     return data; 
    } 

} 

和上面的程序是給我的輸出如下:

PBKDF2 $ SHA256 $ 901 $ v2DdYPk47r/I3aQJ $ N0Y3MjZENzVEOTE5MDcxQkNEOEM5MTAyREQ2MjdEQ0NGNzIzRTZGN0ZCOUYzN0NF

爲什麼我得到不同的密碼長度(最後一部分)。我不明白。 你能幫我找到我的錯誤嗎?

+0

什麼是存儲在'originalPassword'(完全)變量? – Mandy8055

+0

現在硬編碼的字符串。但它會隨機生成/。 –

回答

1

您的問題的答案奠定了各種字符編碼樣式的基礎。而且String的長度不相似是因爲在這兩種情況下使用不同的Encoding(C和Java實現)。

你可以在你的榜樣注意,hash1(因爲它的長度的差異性顯着)變量在UTF-8編碼的Java而C使用ASCII字符編碼(在ANSI標準已經提到)。
另外,UTF-8是一種多字節編碼,它是一種多字節編碼,每個字符使用1到4個字節。 您也可以參考這個:How many bytes does Unicode Character takes?這可能是有趣的,這就是爲什麼哈希值是長在java的長度比C.

希望的答案有助於獲取有關精心研究問題的一些見解。