У меня есть скрипт сервера Python и клиентское приложение Java, и цель состоит в том, чтобы зашифровать данные через сокет.Данные всегда будут строкой.(Я новичок в Java)
Что должно произойти:
Скрипт Python создает сокет и прослушивает соединения, принимает новые соединения, отправляет IV в виде простого текстадля AES CBC PKCS5Padding устанавливает шифры, затем получает зашифрованные данные из приложения Java (дешифрует, затем распечатывает в терминале), затем отправляет зашифрованные данные в приложение Java, а затем закрывает соединение.
Приложение Java подключается к сокету Python, получает IV, устанавливает те же шифры, шифрует простую заполненную строку, отправляет ее на сервер Python, затем ждет ответа, расшифровывает ответ и печатает егона экран.Затем соединение закрывается.
Что на самом деле происходит
Сервер устанавливает сокет, Java-клиент подключается и получает IV, оба устанавливают одинаковые шифры / дешифрование, затем Java-клиент отправляетзашифрованная дополненная строка.сервер Python успешно получает зашифрованный текст, расшифровывает строку и распаковывает ее, и строка отображается правильно.Затем сервер отправляет зашифрованную дополняемую строку клиенту java, клиент получает строку, а затем при дешифровании происходит сбой из-за BadPaddingException.
Я проверил, что заполнение PKCS5 на стороне Python является правильным в соответствии сRFC.Я пробовал другие методы заполнения (дополнение нулями и т. Д.), И ничего не работает.Я также пробовал несколько разных кодировок в строках, я также пробовал M2Crypto (теперь использую pycrypto) и т. Д. Я пробовал использовать CipherInputStream поверх сокета для клиента, и тот же результат.
Ничего не работает.Я все еще думаю, что может быть проблема кодирования между Python и Java, но я застрял в гадости только по поводу того, почему клиенту Java не удается расшифровать.
Python Server:
#!/usr/bin/env python
import os, time, threading, json
from socket import *
import sys, base64
from Crypto.Cipher import AES
from socket import *
### Settings
serverHost = '' # localhost
serverPort = 5555 # non-reserved
masterkey = 'mysecretpassword'
BLOCK_SIZE = 16 # Block-size for cipher (16, 24 or 32 for AES)
#PADDING = '{' # block padding for AES
# PKCS5 Padding
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s : s[0:-ord(s[-1])]
# generate new IV's - why you ask? ... just look at WEP
def createCipher(key):
iv = os.urandom(16)
return (AES.new(key, AES.MODE_CBC, iv), iv)
class IRCTalkServer(threading.Thread):
def __init__(self, masterkey, host='', port=5555):
try:
self.sockobj = socket(AF_INET, SOCK_STREAM) # create TCP socket obj
self.sockobj.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # make port reusable
self.sockobj.bind((host, port)) # bind socket to port
self.sockobj.listen(5) # listen, allow 5 pending connects
if host == '': host='localhost'
print "Started server on %s:%d" % (host, port)
except:
print "Error starting server"
sys.exit(0)
threading.Thread.__init__(self)
self.die = False # loop killer
self.masterkey = masterkey
self.host = host
self.port = port
def run(self):
try:
while True and not self.die: # infinite loop unless called to quit
connection, address = self.sockobj.accept()
print 'Server connected by ', address
# generate cipher and get first IV - prevent same WEP hacks
#paddedKey = keypad(masterkey)
#print "master key:", masterkey, " - padded key:", paddedKey, " - diff key:", keypad('test')
self.cipher, self.iv = createCipher(masterkey)
print "IV:", self.iv.encode('hex'), "Sending IV: ", repr(self.iv)
connection.send("%s%s" % (self.iv.encode('hex'),'\n')) # send iv first
while True and not self.die: # read from client
print "waiting for client"
data = connection.recv(10485760)
print "recieved from client:", repr(data.rstrip())
if not data:
print "NO DATA"
break
dataCheck, JSON = self.decryptData(data.rstrip())
print 'Recieved from Client:', repr(JSON)
#print 'Recieved from Client:', repr(data)
#if dataCheck:
#senddata = self.encryptData('SUCCESS')
#print "Size of compresseddata:", len(senddata)
#connection.send(senddata)
#morestuff = 'abc123def456'*int(10000/9)
#senddata = self.encryptData(['test', morestuff, 'test1', {'key': 'value'}, 2223])
#print "Size of compresseddata:", len(senddata)
#connection.send(senddata)
print "Sending reply to client..."
senddata = self.encryptData('test')
print "reply data:", repr("%s%s" % (senddata, "\n"))
connection.send("%s%s" % (senddata, "\n"))
#connection.send("Hello back mr android!")
#successReply = connection.recv(256) # only for "END REQUEST"
break
print "Closing connection... \n\n"
connection.close()
except:
print "exception on try loop"
pass # an error occurred, just drop it, the client will try again later
def encryptData(self, plaintext):
# convert to json string, pad the string, then encrypt, then compress
#JSON = json.dumps(plaintext, separators=(',',':'))
JSON = plaintext
#print "Size of JSON:", len(JSON)
ciphertext = pad(unicode(JSON))
print "padded text:", repr(ciphertext)
ciphertext = self.cipher.encrypt(ciphertext)
print "ciphertext:", repr(ciphertext), "|", len(ciphertext), "|", ciphertext
ciphertext = ciphertext.encode('hex').upper()
print "hexified text:", repr(ciphertext)
#ciphertext = self.cipher.encrypt(pad(JSON)).encode('hex').upper()
print "Size of ciphertext:", len(ciphertext)
return ciphertext
def decryptData(self, ciphertext):
try:
# decompress data to ciphertext, decrypt, convert to json
print "length of ciphertext:", len(ciphertext)
ptext = ciphertext.decode('hex')
print "unhexifed:", repr(ptext)
ptext = self.cipher.decrypt(ptext)
print "decrypted:", repr(ptext)
ptext = unpad(ptext)
print "unpadded:", repr(ptext)
#ptext = unpad(self.cipher.decrypt(ciphertext.decode('hex')))
print "ptext: ", repr(ptext)
JSON = ptext
#plaintext = unpad(self.cipher.decrypt(ciphertext))
##JSON = json.loads(plaintext)
#JSON = plaintext
except:
print "Error on decryption"
JSON = None
return (True, JSON)
def addToQueue(self, data):
pass
def getFromQueue(self):
pass
testserver =IRCTalkServer(masterkey)
testserver.start()
testserver.join()
Java-клиент: (части этого кода все еще должны быть правильно зачислены - [я просто еще не сделал это])
import java.io.*;
import java.util.*;
import java.net.*;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
//import javax.crypto.CipherInputStream;
//import javax.crypto.CipherOutputStream;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.spec.SecretKeySpec;
class clientHandler {
/*
* This class sets up AES CBC encryption for the socket,
* new instance for every connection since the IV changes
*/
// Declare variables
private Cipher ecipher;
private Cipher dcipher;
Socket testSocket = null;
//DataOutputStream out = null;
//DataInputStream in = null;
PrintWriter out = null;
BufferedReader in = null;
String masterkey = "mysecretpassword";
static final String HEXES = "0123456789ABCDEF";
public static String byteToHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
public static byte[] hexToByte(String hexString) {
int len = hexString.length();
byte[] ba = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
ba[i/2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i+1), 16));
}
return ba;
}
public String encrypt(String plaintext) {
// encrypt string
try {
byte[] cipherbyte = ecipher.doFinal(plaintext.getBytes("UTF-8"));
//String ciphertext = new String(ecipher.doFinal(plaintext.getBytes("UTF8")));
return byteToHex(cipherbyte);
} catch (Exception e){
e.printStackTrace();
return null;
}
}
public String decrypt(String ciphertext) {
// decrypt hex string
try {
System.out.println("decrypt byte length: " + hexToByte(ciphertext).length);
String tp = new String(hexToByte(ciphertext), "UTF-8");
System.out.println("toString(): " + tp);
String plaintext = new String(dcipher.doFinal(hexToByte(ciphertext.trim())), "UTF-8");
//String plaintext = new String(dcipher.doFinal(ciphertext.getBytes("UTF8")), "UTF-8");
return plaintext;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void setupCrypto(byte[] iv, String key) {
// setup AES CBC encryption
// convert IV and key to byte array for crypto
try {
System.out.println("Setting up Crypto...");
//byte[] ivb = iv.getBytes("UTF8");
byte[] keyb = key.getBytes("UTF8");
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
SecretKeySpec skey = new SecretKeySpec(keyb, "AES");
ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
ecipher.init(Cipher.ENCRYPT_MODE, skey, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, skey, paramSpec);
} catch (Exception e) {
System.err.println("Error:" + e);
}
}
public void startServer() {
// starts server
try {
System.out.println("Connecting to Server");
testSocket = new Socket("localhost", 5555);
//out = new DataOutputStream(testSocket.getOutputStream());
//in = new DataInputStream(testSocket.getInputStream());
out = new PrintWriter(testSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(testSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Uknown Host");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection");
}
}
public void androidClientHandler() {
// actual communication
if (testSocket != null && out != null && in != null) {
try {
System.out.println("Waiting for IV..");
String iv;
iv = in.readLine();
byte [] ivb = hexToByte(iv);
System.out.println("Got IV..." + iv);
setupCrypto(ivb, masterkey);
String ciphertext;
String plaintext;
System.out.println("Sending \"test\" to server");
//out.writeBytes("test\n");
ciphertext = encrypt("test");
System.out.println("Sent: " + ciphertext);
out.println(ciphertext);
System.out.println("Waiting for Server to reply");
String responseLine;
responseLine = in.readLine().replaceAll("\\\\n", "");
System.out.println("Recieved from Server: " + responseLine + " - length: " + responseLine.length());
plaintext = decrypt(responseLine);
System.out.println("Recieved from Server: " + plaintext);
System.out.println("Closing Connection");
out.close();
in.close();
testSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host:" + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}
public void javaIsGay() {
startServer();
androidClientHandler();
}
public static void main(String[] args) {
System.setProperty("file.encoding", "UTF-8");
clientHandler c = new clientHandler();
c.javaIsGay();
}
}
Вывод Python-сервера:
Started server on localhost:5555
Server connected by ('127.0.0.1', 59683)
IV: c54aae0a5c43f547f0355ee7a0ee38c1 Sending IV: '\xc5J\xae\n\\C\xf5G\xf05^\xe7\xa0\xee8\xc1'
waiting for client
recieved from client: 'BBE7E09093625204CD3F7B755066419D'
length of ciphertext: 32
unhexifed: '\xbb\xe7\xe0\x90\x93bR\x04\xcd?{uPfA\x9d'
decrypted: 'test\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'
unpadded: 'test'
ptext: 'test'
Recieved from Client: 'test'
Sending reply to client...
padded text: u'test\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c'
ciphertext: '\x9fT\xfc\xf0\xa8\xc2\xd3N*\x8f\x8e~\xc7\x8a\xbfR' | 16 | �T�����N*~NJ�R
hexified text: '9F54FCF0A8C2D34E2A8F8E7EC78ABF52'
Size of ciphertext: 32
reply data: '9F54FCF0A8C2D34E2A8F8E7EC78ABF52\n'
Closing connection...
Вывод клиента Java:
Connecting to Server
Waiting for IV..
Got IV...c54aae0a5c43f547f0355ee7a0ee38c1
Setting up Crypto...
Sending "test" to server
Sent: BBE7E09093625204CD3F7B755066419D
Waiting for Server to reply
Recieved from Server: 9F54FCF0A8C2D34E2A8F8E7EC78ABF52 - length: 32
decrypt byte length: 16
toString(): �T����N*��~NJ�R
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:317)
at javax.crypto.Cipher.doFinal(Cipher.java:1813)
at clientHandler.decrypt(SocketClient.java:70)
at clientHandler.androidClientHandler(SocketClient.java:134)
at clientHandler.javaIsGay(SocketClient.java:151)
at clientHandler.main(SocketClient.java:157)
Recieved from Server: null
Closing Connection