Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/208.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android客户端,Python服务器-AES+;RSA加密-导致:pad块损坏_Python_Android_Encryption_Aes_Rsa - Fatal编程技术网

Android客户端,Python服务器-AES+;RSA加密-导致:pad块损坏

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

我正在尝试从服务器发送/接收加密消息。服务器使用Python,而Java用于Android。我正在做以下工作:

  • 将RSA公钥发送到服务器
  • 使用AES生成(密钥+IV)和加密基础数据
  • 使用收到的RSA公钥加密(密钥+IV)(作为JSON)
  • 通过套接字将RSA加密的AES对发送到客户端
  • 发送AES加密数据
  • 当接收AES对并使用RSA私钥对其解密时,接收到的数据匹配
  • 尝试使用收到的AES密钥解密AES数据时失败
  • 在这两种平台上,当尝试用这两种方法进行加密/解密时,它都能完美地工作。 我相信我从JSON中获取AES(key+IV)的方式是有原因的,但这就是我多次发现的

    失败:

        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就足够了,它通常比自建传输层安全性要好得多。