Android客户端,Python服务器-AES+;RSA加密-导致:pad块损坏
我正在尝试从服务器发送/接收加密消息。服务器使用Python,而Java用于Android。我正在做以下工作:Android客户端,Python服务器-AES+;RSA加密-导致:pad块损坏,python,android,encryption,aes,rsa,Python,Android,Encryption,Aes,Rsa,我正在尝试从服务器发送/接收加密消息。服务器使用Python,而Java用于Android。我正在做以下工作: 将RSA公钥发送到服务器 使用AES生成(密钥+IV)和加密基础数据 使用收到的RSA公钥加密(密钥+IV)(作为JSON) 通过套接字将RSA加密的AES对发送到客户端 发送AES加密数据 当接收AES对并使用RSA私钥对其解密时,接收到的数据匹配 尝试使用收到的AES密钥解密AES数据时失败 在这两种平台上,当尝试用这两种方法进行加密/解密时,它都能完美地工作。 我相信我从JSON
I/System.out: MESSAGE: {"key": "bgOQ0c9xJVI60BrLUzSGK8IDyM9sVrdd", "iv": "2FbQMXqMrd4fDR4V"}
W/System.err: javax.crypto.BadPaddingException: pad block corrupted
at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher.doFinal(BaseBlockCipher.java:1337)
W/System.err: at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:1170)
at javax.crypto.Cipher.doFinal(Cipher.java:2055)
at com.example.tests.encrypt.AES.decrypt(AES.java:62)
at com.example.tests.encrypt.AES.decrypt(AES.java:50)
at com.example.tests.server.Server$ReceivingThread.run(Server.java:66)
at java.lang.Thread.run(Thread.java:764)
下面是一些代码
爪哇:
接收数据:
byte[] in = Base64.decode(fromServerStream.readLine(), Base64.DEFAULT);
byte[] in2 = Base64.decode(fromServerStream.readLine(), Base64.DEFAULT);
if (in != null && in2 != null) {
String keys = RSA.decrypt(in);
System.out.println("MESSAGE: " +keys);
String msg2 = AES.decrypt(in2, keys);
System.out.println(msg2);
}
生成密钥:
public static void generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(Consts.RSA);
kpg.initialize(Consts.RSASize);
KeyPair kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
}
获取PubKey作为字符串(目前仅使用案例“PEM”):
RSA解密:
public static String decrypt(byte[] result)
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException {
Cipher cipher1 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher1.doFinal(result), Consts.charsetEncoding);
}
public static String decrypt(byte[] plaintext, String JSONKey) throws Exception
{
JSONObject jsonObject = new JSONObject(JSONKey);
String key = jsonObject.getString("key");
String iv = jsonObject.getString("iv");
return AES.decrypt(
plaintext,
new SecretKeySpec(key.getBytes(Consts.charsetEncoding), Consts.AES),
iv.getBytes(Consts.charsetEncoding));
}
public static String decrypt(byte[] cipherText, SecretKey key, byte[] IV)
{
try {
Cipher cipher = Cipher.getInstance(Consts.AES);
IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
return new String(cipher.doFinal(cipherText), Consts.charsetEncoding);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
AES解密:
public static String decrypt(byte[] result)
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException {
Cipher cipher1 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher1.doFinal(result), Consts.charsetEncoding);
}
public static String decrypt(byte[] plaintext, String JSONKey) throws Exception
{
JSONObject jsonObject = new JSONObject(JSONKey);
String key = jsonObject.getString("key");
String iv = jsonObject.getString("iv");
return AES.decrypt(
plaintext,
new SecretKeySpec(key.getBytes(Consts.charsetEncoding), Consts.AES),
iv.getBytes(Consts.charsetEncoding));
}
public static String decrypt(byte[] cipherText, SecretKey key, byte[] IV)
{
try {
Cipher cipher = Cipher.getInstance(Consts.AES);
IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
return new String(cipher.doFinal(cipherText), Consts.charsetEncoding);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
常数:
// ENCODING
public static final String encoding = "ASCII";
public static final Charset charsetEncoding = StandardCharsets.US_ASCII;
// AES
public static final String AES = "AES";
public static final int AESSize = 256;
public static final int IVSize = 16;
===============================================================
Python/服务器端:
首先,输出:
'{"type": "keyExchange", "pubKey": "-----BEGIN RSA PUBLIC KEY-----\\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjfqo/3Cqw28s8AuXq1/keHgPzcrthSvy\\npepeuu3RANiORN2MIjQjF+KEQPsdNphtBvHA/v4l/9MmrcRFZlLf+1KXnjMWSkr+0lnpVpu7x7Mf\\nnP0RBSS5I5wpxq7FmaTaIGIdDk5G7SZVLChdXDXtpoU95UJ/VLyJe7X17N3nYPIAPxsOMqzKZFN1\\n1EbgmyeSWkU6y5OA3Txggd6csjKq+BGDaVsex50PdS7bP43j2r/+wRb5zDhXI9nHsG6Sb49D1TE4\\ncJksRzkKc1NuBzyY4qmq/UQDdDSowDavEF2hf6zU9xo4o5rvIgGAF+ZHUUMS7qixmx4Vln88WnbW\\nDWCD8J7MRprJmb6zN8YgePQPzbf1527oBW9jCi9OFI7+FPKZOodvMTR6hZSon8LykVY4K8LifsXK\\n7UWy1DljBDakzWJZGHZv9dyXrCeZNxmYTrIWeh19rMWKMoX/X0mWPVPHzfAxqVnryrWsBBu+ImQP\\nAZvnY3lwvOii11T2sv0pXwk+hUKNiA1DmDF8dPQxTeX0I95Sum1VvDFrNNeEsS4NAfeOvnjIwl4Z\\npR0inRbbw7lZmQHerk4kN/x7NM27eOmi8/y6D3G9/Rf4yqLDewA7Qoe+El5VNW7Zd1Iw4sr8JGmb\\nm75mqcZlYtCaweJxfjmHoL4jvJnq5yjxGFyjI/tslxcCAwEAAQ==\\n-----END RSA PUBLIC KEY-----"}'
KEY: bgOQ0c9xJVI60BrLUzSGK8IDyM9sVrdd
IV: 2FbQMXqMrd4fDR4V
b'ASJzulQs9qX3i3k8zMIvTlaNdwrsy4K0GgD/W3L+seH56uTtJ7FO8Mev0j+hwHuGkUj4UZ56MTolYutPpwgnlYcWlzIFjPgKbAG/MwsYdp+JoTS8bSo9YS8x0+ARhXmLa/mQefGUq/0l1YKkVB/SzXp27ni802c4ApPSkP98xp/IhZZgNQswB0c6Mm29o8MTw1/bv3lV8bhkHLtWVDClz91RKz53jTH6XpAFsLtk90ZgX7hRZSO+jAwFlCkRNLKxqwjVANtRuaWm1Agmf10HwKYBVSzgXLpC8+hT90Eicj/8TOj1HSnE/IUweSz21aQbm101H+VP76mbVofq9ID4Mmc+6a+VP2/DHNHUQO0sJuoNUecoe31UaXjHShLaPY4kFHMloOKcuZUsQdnBoTaak3W68pJ5AmHICcZ689FO2e/6QaUF9YzyP1eB3nQpxP48eR2KlK+I288dycMTpapfNWThWHOa+bEjGobLL26+pk3lixyw56RRd+YZ4Fm+omnnpHdtW3Qn388HzmU9Hz0ho/r88ofpVcdxBICLNBjwRgGt5ArfGo4wNvuS7VceFohqk3foVXgkZmHsakjewiqosSk2gqP0yeux0DRweL5vOMo08kMbGlz/Zr8HWcM7UkDbFcGLALY+sf8yu/3nnv/gw0Z45o7TopRiLW8m0cvKYOk='
b'3JRcYYCjwt8/RSuis6TjdJOpxOV4OzIJODkLRGXJb6d89r+cwgZ9s7kcgR0uUOvR'
接收+发送(测试):
整个AES:
@staticmethod
def generateKey():
return \
(''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for x in range(Consts.AESSize))).encode(Consts.encoding), \
(''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for x in range(Consts.IVSize))).encode(Consts.encoding)
@staticmethod
def padding(data):
if len(data) % 16 != 0:
return '{}{}'.format(data, ' ' * (16 - len(data) % 16))
return data
@staticmethod
def encrypt(data):
key, iv = MAES.generateKey()
data = MAES.padding(data)
return base64.b64encode(key), \
base64.b64encode(iv), \
base64.b64encode(AES.new(key, AES.MODE_CBC, iv).encrypt(data.encode(Consts.encoding)))
@staticmethod
def decrypt(data, key, iv):
return AES.new(base64.b64decode(key), AES.MODE_CBC, base64.b64decode(iv)).decrypt(base64.b64decode(data)).strip().decode()
整个RSA:
@staticmethod
def generateKey():
return RSA.generate(Consts.RSASize)
@staticmethod
def getKeyFromString(str):
return RSA.import_key(bytes(str, encoding=Consts.encoding))
@staticmethod
def encrypt(msg, public):
return base64.b64encode(PKCS1_OAEP.new(public).encrypt(msg.encode(Consts.encoding)))
@staticmethod
def decrypt(data, keyPair):
return PKCS1_OAEP.new(keyPair).decrypt(base64.b64decode(data)).decode(Consts.encoding)
最后是常数:
encoding = "ASCII"
AES = "AES"
AESSize = 32
IVSize = 16
RSA = "RSA"
RSASize = 4096
编辑:
如果您有任何问题,请阅读来自Maarten Bodewes的答案评论。在我看来,您有两个主要问题
Const.AES
没有指定AES/CBC/PKCS5Padding
(),相反,它很可能默认为ECB模式,用于AES
Python中的padding方法也不执行PKCS#7 padding,而是使用空格字符:
def填充(数据):
如果len(数据)%16!=0:
返回'{}{}'。格式(数据,'*(16-len(数据)%16))
返回数据
这不是一个好主意,请改用PKCS#7填充
请注意,整个方案相对不安全,只能与TLS传输结合使用。然后可以使用它在客户端上安全地存储静态数据。您需要对数据进行身份验证(签名)签名,并确保如果要在不安全的连接上使用,则填充预言不适用-设计传输安全性不适合未经初始化的人。只是为了澄清。。Python更改:``@staticmethod def pad(m):返回m+chr(16-len(m)%16)*(16-len(m)%16)@staticmethod def unpad(ct):返回ct[:-ord(ct[-1])]```并在Android设备中返回指定的常量。现在一切正常,谢谢!再次感谢@对于Python端,实际上不需要自定义填充。PyCryptodome在中支持PKCS7填充。由于我在使用“AES/CBC/PKCS5Padding”使用Java加密AES时遇到问题,我想我需要指出,您只使用“AES”生成密钥,而使用“AES/CBC/PKCS5Padding”加密(否则,KeyGenerator将抛出“NosuchagorithmException”)是,任何AES操作模式的密钥类型将仅为“AES”;分组密码接受密钥,而这一点不会改变。这取决于。对于传输层安全性,我会说不。但是,您可能希望在以后存储加密的数据,或者跨多个TLS“跃点”(解密防火墙、负载平衡器、数据包检查实用程序等等)对其进行保护。然而,一般来说,TLS就足够了,它通常比自建传输层安全性要好得多。