Это дополнение к моей предыдущей статье «
Шифровка потока информации PHP-HTTP-Qt». Для того что бы понять о чём тут речь, прочитайте её сначала. Здесь приводится простенькая демонстрационная программа-клиент на Java, которая делает то же самое, что я сделал там на C++/Qt, то есть обеспечивает приём и расшифровку данных по тому же протоколу. Она работает с тем же самым серверным скриптом на PHP. Принятые расшифрованные данные (в моём случае XML) выводятся в стандартный поток вывода. Вот исходный код (URL-скрипта и пароли я естесвенно убрал):
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Array;
import java.io.*;
import java.net.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import gnu.crypto.Registry;
import gnu.crypto.hash.MD5;
import gnu.crypto.jce.GnuCrypto; // GNU-JCE провайдер алгоритма TwoFish
// import iaik.security.provider.IAIK; // IAIK-JCE провайдер алгоритма TwoFish
public class MainClass {
final static String surl = "
http://......./xml.php"; // "baseurl()+"/xml.php";
final static String iv0 = "i.vector";
final static String key0 = ".............."; // Hex encoded
final static String password0 = "........."; // personal password in plain text
// prepare cipher
public static Cipher createCipher(int mode, byte[] key, byte[] ivBytes) throws
UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchProviderException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException
{
IvParameterSpec iv = new IvParameterSpec(ivBytes);
SecretKey secretKey = new SecretKeySpec( key, "Twofish" );
// get Cipher and init it for encryption
//Cipher cipher = Cipher.getInstance("Twofish/CBC/NoPadding", "IAIK"); // IAIK
Cipher cipher = Cipher.getInstance("Twofish/CBC/NoPadding", Registry.GNU_CRYPTO); // GNU
cipher.init( mode, secretKey, iv );
return cipher;
}
// encrypt string
public static String encrypt(String source, String key, byte[] iv)
throws
UnsupportedEncodingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException,
NoSuchAlgorithmException,
NoSuchProviderException,
NoSuchPaddingException,
InvalidAlgorithmParameterException
{
Cipher cipher = createCipher( Cipher.ENCRYPT_MODE, key.getBytes("UTF-8"), iv );
// encrypt data
while ( source.length() % cipher.getBlockSize() !=0 ) source+="\0"; // padding
byte[] cipherText = cipher.doFinal( source.getBytes("UTF-8") );
// перевод cipherText в HEX-представление
String encryptedString = "";
for (int i = 0; i < cipherText.length; i++) {
encryptedString += String.format("%02x", cipherText[i]);
} // encryptedText = Base64Coder.encodeLines(encryptedText);
return encryptedString;
}
public static void main(String[] args) {
System.out.println("DecryptorTest HELLO");
// Security.addProvider( new IAIK() ); // using IAIK Security Provider
java.security.Security.addProvider(new GnuCrypto());
// Using Hex in Apache Commons:
// byte[] bytes = Hex.decodeHex(key0.toCharArray());
StringBuilder keyc = new StringBuilder();
for (int i = 0; i < key0.length(); i+=2) {
String str = key0.substring(i, i+2);
keyc.append((char)Byte.parseByte(str, 16));
}
System.out.println("DecryptorTest: Common secret key (plain) =" + keyc);
MD5 md5 = new MD5();
//IMessageDigest md5 = HashFactory.getInstance("MD5");
byte[] iv;
try {
iv = iv0.getBytes( "UTF-8" );
} catch (UnsupportedEncodingException e1) {
System.out.println("DecryptorTest: Error: UnsupportedEncodingException (UTF-8)");
return;
}
System.out.println("DecryptorTest: Common initialization vector length (bytes) =" + iv.length);
md5.update(iv, 0, iv.length);
String ivh = "";
iv = md5.digest();
for (int i = 0; i < iv.length; i++) {
ivh += String.format("%02x", iv[i] );
}
System.out.println("DecryptorTest: Common initialization vector (MD5) =" + ivh);
// encrypt the user password and convert it to Hex
String passwordh;
try {
passwordh = encrypt( password0, keyc.toString(), iv );
} catch ( InvalidKeyException
| UnsupportedEncodingException
| IllegalBlockSizeException
| BadPaddingException
| NoSuchAlgorithmException
| NoSuchProviderException
| NoSuchPaddingException
| InvalidAlgorithmParameterException e)
{
System.out.println("DecryptorTest: Error: cannot encrypt user password! Exception="+e.toString());
return;
}
System.out.println("DecryptorTest: Personal password (encripted, hex) =" + passwordh);
md5.reset();
try {
md5.update(password0.getBytes("UTF-8"), 0, password0.getBytes("UTF-8").length);
} catch (UnsupportedEncodingException e) {
System.out.println("DecryptorTest: Error: cannot prepare password (no UTF-8 encoding)");
return;
}
byte[] pwd5 = md5.digest();
//System.out.println("DecryptorTest: Personal password (MD5, hex) =" + password5);
int keysize;
keysize = 32; // Cipher.getMaxAllowedKeyLength("Twofish/CBC/NoPadding");
System.out.println("DecryptorTest: maximum key size ="+keysize );
URL url;
try {
url = new URL(surl);
} catch (MalformedURLException e) {
System.out.println("DecryptorTest: Error: Malformed URL");
return;
}
HttpURLConnection conn;
InputStream stream;
try {
conn = (HttpURLConnection) url.openConnection();
String post;
post = "user=shestero";
post+= "&password="+passwordh;
conn.setDoOutput(true); // мы будем писать POST данные
conn.setDoInput(true);
OutputStreamWriter out =
new OutputStreamWriter( conn.getOutputStream(), "UTF-8" );
out.write(post);
// out.write("\r\n"); // перевод строки попадает в значения, передаваемые POST-ом
out.close();
stream = conn.getInputStream();
stream.mark(1);
int i0 = 0;//stream.read();
BufferedReader r;
if (i0==0)
{
stream.skip(32); // skip header
// encrypted
System.out.println("DecryptorTest: Note: data comes encrypted!");
byte[] key2 = new byte[32];
Arrays.fill(key2,(byte)0);
int j=0;
for (int i=0; i() || i)
{
if (i()) key2[j++]=keyc.toString().substring(i,i+1).getBytes()[0];
if (i) key2[j++]=pwd5[i];
if (j>=keysize)
break;
}
System.out.println("DecryptorTest: Personal key to decript reply =["+key2+"]");
// TODO: Fix key size
if (j<=16) j=16; else if (j<=24) j=24; else if (j<32) j=32;
System.out.println("DecryptorTest: key2.length="+j);
Cipher cipher = createCipher( Cipher.DECRYPT_MODE, key2, iv );
r = new BufferedReader( new InputStreamReader( new CipherInputStream( stream, cipher ) ) );
}
else
{
// plain
stream.reset();
r = new BufferedReader( new InputStreamReader( stream ) );
System.out.println("DecryptorTest: Warning: data comes unencrypted!");
}
// Чтение строка за строкой для проверки
System.out.println("====[REPLY FROM SERVER:]===========================");
String inputLine;
while ((inputLine = r.readLine()) != null)
{
System.out.println(inputLine);
}
r.close();
System.out.println("====[SUCESS]=======================================");
} catch (IOException e) {
System.out.println("DecryptorTest: Error: IOException; URL="+surl);
} catch ( InvalidKeyException
| NoSuchAlgorithmException
| NoSuchProviderException
| NoSuchPaddingException
| InvalidAlgorithmParameterException e)
{
System.out.println("DecryptorTest: Error: cannot decode: Exception="+e.toString());
}
System.out.println("DecryptorTest BYE");
}
}
Исходник обработан:
Java2html Ради алгоритма Twofish я использовал из
GNU-JCE , а также пробовал коммерческий
IAIK с закрытым исходным кодом.
См. также:
http://www.cryptix.org ,
http://bouncycastle.org(
Comments |
Comment on this)