2017-05-29 105 views
0

我正在尋找加密PHP服務器和Java客戶端之間的數據。單獨的代碼工作正常,我想堅持在PHP服務器上使用OpenSSL。PHP和Java之間的加密

做任何你看到的東西,我很想念這裏,我在嘗試的PHP加密的字符串解碼時的錯誤:

[刪除非工作代碼]

更新 - 我能得到它使用openssl。這裏是工作PHP和Java文件的GIT倉庫。

https://github.com/chaudhuri-ab/CrossPlatformCiphers

+0

這或許SO【答案】(https://stackoverflow.com/a/20770158/1889768)會幫助你。 – Abbas

+0

如果你使用SSL,你爲什麼要加密?使用https url和android會自動進行加密/解密。只需設置服務器即可使用https。真的不建議你自己做這樣的事情,它很容易得到微妙的東西錯誤 - 沒有足夠的隨機值(蘭德是不夠的),壞IVs等。 –

+0

@加貝 - 我完全同意你的發言。這是客戶正在尋求的特殊設計要求。所以我需要找到一個解決方案。 –

回答

2

工作版本,可以發現 - https://github.com/chaudhuri-ab/CrossPlatformCiphers

有些事情要記住的是,如果你沒有在PHP中指定OPENSSL_RAW_DATA,那麼數據將被加密爲ba se64。那讓我失望了。

PHP:

class PHP_AES_Cipher { 

    private static $OPENSSL_CIPHER_NAME = "aes-128-cbc"; //Name of OpenSSL Cipher 
    private static $CIPHER_KEY_LEN = 16; //128 bits 

    /** 
    * Encrypt data using AES Cipher (CBC) with 128 bit key 
    * 
    * @param type $key - key to use should be 16 bytes long (128 bits) 
    * @param type $iv - initialization vector 
    * @param type $data - data to encrypt 
    * @return encrypted data in base64 encoding with iv attached at end after a : 
    */ 

    static function encrypt($key, $iv, $data) { 
     if (strlen($key) < PHP_AES_Cipher::$CIPHER_KEY_LEN) { 
      $key = str_pad("$key", PHP_AES_Cipher::$CIPHER_KEY_LEN, "0"); //0 pad to len 16 
     } else if (strlen($key) > PHP_AES_Cipher::$CIPHER_KEY_LEN) { 
      $key = substr($str, 0, PHP_AES_Cipher::$CIPHER_KEY_LEN); //truncate to 16 bytes 
     } 

     $encodedEncryptedData = base64_encode(openssl_encrypt($data, PHP_AES_Cipher::$OPENSSL_CIPHER_NAME, $key, OPENSSL_RAW_DATA, $iv)); 
     $encodedIV = base64_encode($iv); 
     $encryptedPayload = $encodedEncryptedData.":".$encodedIV; 

     return $encryptedPayload; 

    } 

    /** 
    * Decrypt data using AES Cipher (CBC) with 128 bit key 
    * 
    * @param type $key - key to use should be 16 bytes long (128 bits) 
    * @param type $data - data to be decrypted in base64 encoding with iv attached at the end after a : 
    * @return decrypted data 
    */ 
    static function decrypt($key, $data) { 
     if (strlen($key) < PHP_AES_Cipher::$CIPHER_KEY_LEN) { 
      $key = str_pad("$key", PHP_AES_Cipher::$CIPHER_KEY_LEN, "0"); //0 pad to len 16 
     } else if (strlen($key) > PHP_AES_Cipher::$CIPHER_KEY_LEN) { 
      $key = substr($str, 0, PHP_AES_Cipher::$CIPHER_KEY_LEN); //truncate to 16 bytes 
     } 

     $parts = explode(':', $data); //Separate Encrypted data from iv. 
     $decryptedData = openssl_decrypt(base64_decode($parts[0]), PHP_AES_Cipher::$OPENSSL_CIPHER_NAME, $key, OPENSSL_RAW_DATA, base64_decode($parts[1])); 

     return $decryptedData; 
    } 

} 

的Java:

package ciphers; 

import javax.crypto.Cipher; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.SecretKeySpec; 

import java.util.Base64; 

public class Java_AES_Cipher { 

    private static String CIPHER_NAME = "AES/CBC/PKCS5PADDING"; 
    private static int CIPHER_KEY_LEN = 16; //128 bits 

    /** 
    * Encrypt data using AES Cipher (CBC) with 128 bit key 
    * 
    * 
    * @param key - key to use should be 16 bytes long (128 bits) 
    * @param iv - initialization vector 
    * @param data - data to encrypt 
    * @return encryptedData data in base64 encoding with iv attached at end after a : 
    */ 
    public static String encrypt(String key, String iv, String data) { 
     try { 
      if (key.length() < Java_AES_Cipher.CIPHER_KEY_LEN) { 
       int numPad = Java_AES_Cipher.CIPHER_KEY_LEN - key.length(); 

       for(int i = 0; i < numPad; i++){ 
        key += "0"; //0 pad to len 16 bytes 
       } 

      } else if (key.length() > Java_AES_Cipher.CIPHER_KEY_LEN) { 
       key = key.substring(0, CIPHER_KEY_LEN); //truncate to 16 bytes 
      } 


      IvParameterSpec initVector = new IvParameterSpec(iv.getBytes("UTF-8")); 
      SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); 

      Cipher cipher = Cipher.getInstance(Java_AES_Cipher.CIPHER_NAME); 
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec, initVector); 

      byte[] encryptedData = cipher.doFinal((data.getBytes())); 

      String base64_EncryptedData = Base64.getEncoder().encodeToString(encryptedData); 
      String base64_IV = Base64.getEncoder().encodeToString(iv.getBytes("UTF-8")); 

      return base64_EncryptedData + ":" + base64_IV; 

     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 

     return null; 
    } 

    /** 
    * Decrypt data using AES Cipher (CBC) with 128 bit key 
    * 
    * @param key - key to use should be 16 bytes long (128 bits) 
    * @param data - encrypted data with iv at the end separate by : 
    * @return decrypted data string 
    */ 

    public static String decrypt(String key, String data) { 
     try { 

      String[] parts = data.split(":"); 

      IvParameterSpec iv = new IvParameterSpec(Base64.getDecoder().decode(parts[1])); 
      SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); 

      Cipher cipher = Cipher.getInstance(Java_AES_Cipher.CIPHER_NAME); 
      cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); 

      byte[] decodedEncryptedData = Base64.getDecoder().decode(parts[0]); 

      byte[] original = cipher.doFinal(decodedEncryptedData); 

      return new String(original); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 

     return null; 
    } 

} 
2

我無法弄清楚爲什麼你的方法失敗。順便說一句,我是這樣做的,

的Java

import com.sun.org.apache.xml.internal.security.utils.Base64; 

import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 
import java.security.Key; 

public class MyClass { 

    public static void main(String[] args) { 
     String data = "Arnab C"; 
     final String enc = DarKnight.getEncrypted(data); 
     System.out.println("Encrypted : " + enc); 
     System.out.println("Decrypted : " + DarKnight.getDecrypted(enc)); 
    } 

    static class DarKnight { 

     private static final String ALGORITHM = "AES"; 

     private static final byte[] SALT = "tHeApAcHe6410111".getBytes();// THE KEY MUST BE SAME 
     private static final String X = DarKnight.class.getSimpleName(); 

     static String getEncrypted(String plainText) { 

      if (plainText == null) { 
       return null; 
      } 

      Key salt = getSalt(); 

      try { 
       Cipher cipher = Cipher.getInstance(ALGORITHM); 
       cipher.init(Cipher.ENCRYPT_MODE, salt); 
       byte[] encodedValue = cipher.doFinal(plainText.getBytes()); 
       return Base64.encode(encodedValue); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 

      throw new IllegalArgumentException("Failed to encrypt data"); 
     } 

     public static String getDecrypted(String encodedText) { 

      if (encodedText == null) { 
       return null; 
      } 

      Key salt = getSalt(); 
      try { 
       Cipher cipher = Cipher.getInstance(ALGORITHM); 
       cipher.init(Cipher.DECRYPT_MODE, salt); 
       byte[] decodedValue = Base64.decode(encodedText); 
       byte[] decValue = cipher.doFinal(decodedValue); 
       return new String(decValue); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      return null; 
     } 

     static Key getSalt() { 
      return new SecretKeySpec(SALT, ALGORITHM); 
     } 

    } 
} 

PHP

<?php 

$key = "tHeApAcHe6410111"; 

function encrypt($text,$key){ 
    $block = mcrypt_get_block_size('rijndael_128', 'ecb'); 
    $pad = $block - (strlen($text) % $block); 
    $text .= str_repeat(chr($pad), $pad); 
    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_ECB)); 
} 

function decrypt($str, $key){ 
    $str = base64_decode($str); 
    $str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB); 
    $block = mcrypt_get_block_size('rijndael_128', 'ecb'); 
    $pad = ord($str[($len = strlen($str)) - 1]); 
    $len = strlen($str); 
    $pad = ord($str[$len-1]); 
    return substr($str, 0, strlen($str) - $pad); 
} 

$enc = encrypt("Arnab C",$GLOBALS['key']); 
echo "Encrypted : ".$enc."</br>"; 
$dec = decrypt($enc,$GLOBALS['key']); 
echo "Decrypted : ".$dec; 

的Java輸出

加密:PJG1Uu6SjJuuVGf7ApuHAw ==

解密:ARNABÇ

PHP輸出

加密:PJG1Uu6SjJuuVGf7ApuHAw ==

解密:ARNABÇ

+0

它是否適合您在PHP方面的OpenSSL與Mcrypt,這是一個不再積極開發的庫?另外,如果你使用了Iv,它適合你嗎? Thx –

+0

我不知道它是否適用於OpenSSL。嘗試一下。 – theapache64

+0

我確實有工作。 OpenSSL選項有所不同。瞭解默認情況下,PHP中的OpenSSL將生成一個Base64編碼的字符串。回答以上。 Thx和+1作爲回覆。 –

0

我使用的解決方案,從theapache64,但是在PHP 7.2它停止工作,因爲這個Mcrypt已被棄用,後來刪除。所以我改變了代碼和它的工作原理:

function encrypt($data, $key) { 
    return base64_encode(openssl_encrypt($data, "aes-128-ecb", $key, OPENSSL_RAW_DATA)); 
} 

function decrypt($data, $key) { 
    return openssl_decrypt(base64_decode($data), "aes-128-ecb", $key, OPENSSL_RAW_DATA); 
}