2015-10-23 1 views
1

Je suis juste en train de développer un logiciel avec un client Java et un serveur php. Le client Java génère les 2 clés RSA. La clé publique est envoyée via la demande de publication au serveur PHP. Le serveur crypte la réponse avec la clé publique et la renvoie au client Java. Mais je reçois cette erreur:Keygeneration Java, chiffrement php, décryptage Java

Exception in thread "main" org.bouncycastle.crypto.InvalidCipherTextException: unknown block type 
at org.bouncycastle.crypto.encodings.PKCS1Encoding.decodeBlock(Unknown Source) 
at org.bouncycastle.crypto.encodings.PKCS1Encoding.processBlock(Unknown Source) 

Pour autant que je suis arrivé par googler, la clé publique et privée ne correspondent pas ensemble. L'erreur se sur cette ligne: (Si la réponse doit être déchiffré) byte[] encodedCipher = asymmetricBlockCipher.processBlock(messageBytes, 0, messageBytes.length);

Donc, en fait, de ce que je pense qu'il doit y avoir un problème avec l'encodage base64 de la clé publique ou à la transmission de mais je ne pouvais pas en trouver un. Si je echo la clé codée sur le serveur, c'est la même chose que le codé sur le client. Mais je n'ai rien trouvé d'utile sur le cryptage base64 au cours des dernières heures. Pour base64 en java-je utiliser ce 2 classes: import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;

parties de mon client java:

Les clés sont générées: (ils sont enregistrés comme des champs)

D'ici: http://www.mysamplecode.com/2011/08/java-generate-rsa-key-pair-using-bouncy.html

private String publicKey; 
private byte[] privateKey; 

private void generateKeys() throws NoSuchProviderException, NoSuchAlgorithmException { 
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC"); 
    BASE64Encoder base64Encoder = new BASE64Encoder(); 

    SecureRandom rnd = new FixedRand(); 
    generator.initialize(2048, rnd); 

    KeyPair keyPair = generator.generateKeyPair(); 
    this.publicKey = base64Encoder.encode(keyPair.getPublic().getEncoded()).replaceAll("(?:\\r\\n|\\n\\r|\\n|\\r)", "").trim(); 
    this.privateKey = keyPair.getPrivate().getEncoded(); 
} 

La demande du message: (avec apache client http)

private String readUrl(String urlString, String publicKey) throws Exception { 
    HttpClient client = new DefaultHttpClient(); 
    HttpPost post = new HttpPost(urlString); 

    List<NameValuePair> nameValuePairs = new ArrayList<>(1); 
    nameValuePairs.add(new BasicNameValuePair("key", publicKey)); 
    post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 

    HttpResponse response = client.execute(post); 

    BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); 
    String line = ""; 
    StringBuffer responseString = new StringBuffer(); 
    while ((line = rd.readLine()) != null) { 
     responseString.append(line); 
    } 
    return responseString.toString(); 
} 

La partie de décryptage:

private String decrypt(String crypted) throws IOException, InvalidCipherTextException { 
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 

    AsymmetricBlockCipher asymmetricBlockCipher = new RSAEngine(); 
    asymmetricBlockCipher = new org.bouncycastle.crypto.encodings.PKCS1Encoding(asymmetricBlockCipher); 
    BASE64Decoder base64Decoder = new BASE64Decoder(); 
    crypted = new String(base64Decoder.decodeBuffer(crypted)); 
    AsymmetricKeyParameter asymmetricKeyParameter = PrivateKeyFactory.createKey(this.javaKeyToBouncycastle(privateKey)); 
    asymmetricBlockCipher.init(false, asymmetricKeyParameter); 

    byte[] messageBytes = crypted.getBytes(); 
    byte[] encodedCipher = asymmetricBlockCipher.processBlock(messageBytes, 0, messageBytes.length); 

    return new String(encodedCipher); 
} 

private PrivateKeyInfo javaKeyToBouncycastle(byte[] key) throws IOException { 
    ASN1InputStream pkstream = new ASN1InputStream(key); 
    return PrivateKeyInfo.getInstance(pkstream.readObject()); 
} 

Et une partie de mon serveur php: (avec phpseclib)

$key = trim(base64_decode($_POST['key'], true)); 
$rsa = new Crypt_RSA(); 
$rsa->loadKey($key); 
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); 
$crypt = $rsa->encrypt("Hello World"); 
echo base64_encode($crypt); 

Merci :-) Malheureusement, je ne sais pas beaucoup sur le cryptage atm et la plupart des parties de code que j'ai trouvées avec google et les personnalisées, mais je travaille dessus. (projet privé uniquement)

+0

Je ne comprends pas pourquoi vous utilisez la bibliothèque légère de Bouncy Castle au lieu du Java JCE normal ('Cipher'). Vous ne devriez pas utiliser les classes internes 'sun' comme la base 64, Java 8 a une classe' java.util.Base64'. ** Notez que votre code n'est pas sécurisé contre l'homme dans les attaques du milieu **; * n'importe qui * peut vous envoyer la clé publique. Ceci est uniquement sécurisé ** sur TLS ** pour fournir une sécurité au niveau de l'application (par exemple pour stocker les messages côté serveur chiffré). –

+0

@MaartenBodewes J'utilise bouncycastle parce que j'ai trouvé des exemples de code sur Internet. Pourquoi devrais-je éviter les classes «soleil»? La prochaine chose que je vais ajouter est une connexion https, Java doit juste accepter mon certificat startssl. Mais cela ne doit pas être sûr à 100%, néanmoins ce serait bien si c'est le cas. – jhns

+0

Les classes 'sun' du JRE sont des classes d'implémentation internes. Ils ne font pas partie de l'API officielle. Ils peuvent changer ou même disparaître sans avertissement. Si vous construisez par rapport à un "Environnement d'Exécution" dans e.g. Eclipse, ils peuvent même entraîner des erreurs de compilation. Vous pouvez également configurer Java JSSE pour accepter les magasins de clés personnalisés (avec des certificats personnalisés). Actuellement, tout ce que l'attaquant doit faire est d'envoyer sa clé publique au serveur et il crypte heureusement les informations pour lui. C'est assez loin d'être sécurisé. –

Répondre

1

Vous ne devriez pas renvoyer le résultat du codage de base 64 dans une chaîne.

crypted = new String(base64Decoder.decodeBuffer(crypted)); 
... 
byte[] messageBytes = crypted.getBytes(); 

Même si vous effectuez base 64 décodage avant alors une chaîne ne peut pas contenir des données aléatoires ne pas toutes les données représente une chaîne encodée valide. Au lieu de cela, il suffit d'affecter le tableau d'octets à une nouvelle variable, par ex.

byte[] ciphertext = base64Decoder.decodeBuffer(crypted); 

et l'utiliser comme entrée pour le asymmetricBlockCipher.

+0

N'est-ce pas quelques lignes ci-dessus? 'BASE64Decoder base64Decoder = nouveau BASE64Decoder(); crypted = new String (base64Decoder.decodeBuffer (crypté)); ' – jhns

+0

Ah, OK, mais pourquoi encaisseriez-vous le résultat dans une chaîne? Si vous faites cela, vous risquez de perdre des informations. –

+0

Je viens de changer cela en 'byte [] messageBytes = base64Decoder.decodeBuffer (crypté); 'et maintenant ça marche, merci! – jhns