为什么我的java套接字接收到的数组大小大于发送的数组大小?

ezykj2lf  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(423)

我正在创建一个客户机/服务器程序来执行256位aes加密。我从ecdh那里得到我的钥匙。我发送用于表示各种键和字符串的字节数组的大小。我遇到的问题是,当我试图将加密字符串的大小从客户端发送到服务器时,服务器会说我发送的大小比实际发送的要大得多。发送大小适用于所有其他需要发送的字节数组。从客户端发送的加密字符串的大小为16字节。服务器接收的整数大小为276032497字节。我已经检查,我实际上是从客户端发送16字节。
你知道问题是什么吗?


服务器代码:

//generate public key for server
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
        kpg.initialize(256);
        KeyPair kp = kpg.generateKeyPair();
        byte[] ourPk = kp.getPublic().getEncoded();
        String format = kp.getPublic().getFormat();
        int ourPkLength = ourPk.length;

        int arrSize;

        //send client our pk 
        out.writeInt(ourPkLength);
        out.write(ourPk);
        System.out.println("sent PK!");

        //receive pk from client
        arrSize = fromClient.readInt();
        byte[] otherPk = new byte[arrSize];
        fromClient.read(otherPk);
        System.out.println("recived client PK!");

        KeyFactory kf = KeyFactory.getInstance("EC");
        X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
        PublicKey otherPublicKey = kf.generatePublic(pkSpec);

        //Perform key agreement 
        KeyAgreement ka = KeyAgreement.getInstance("ECDH");
        ka.init(kp.getPrivate());
        ka.doPhase(otherPublicKey, true);

        // Send shared secret
        byte[] sharedSecret = ka.generateSecret();

        // Derive a key from the shared secret and both public keys
        MessageDigest hash = MessageDigest.getInstance("SHA-256");
        hash.update(sharedSecret);
        // Simple deterministic ordering
        List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
        Collections.sort(keys);
        hash.update(keys.get(0));
        hash.update(keys.get(1));

        byte[] derivedKey = hash.digest();

        System.out.println("derived key: " + derivedKey + "  length: " + derivedKey.length);

        //Convert byte [] to secret key
        //Define cipher
        SecretKeySpec symmetricKey = new SecretKeySpec(derivedKey, 0, 32, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, symmetricKey, new IvParameterSpec(new byte[16]));

        //receive encrypted message from client and try to decrypt. 
        arrSize = fromClient.readInt();
        System.out.println("array size sent: " + arrSize);
        byte[] decryptArr = new byte[arrSize];
        fromClient.read(decryptArr);
        System.out.println("Recieved encrypted string: " + decryptArr + "    length:   " + decryptArr.length);
        String decryptStr = Base64.getEncoder().encodeToString(cipher.doFinal(decryptArr));

        System.out.println("Decrypted String: " + decryptStr);

客户代码:

//generate public key for client
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
        kpg.initialize(256);
        KeyPair kp = kpg.generateKeyPair();
        byte[] ourPk = kp.getPublic().getEncoded();
        //String format = kp.getPublic().getFormat();
        int ourPkLength = ourPk.length;

    int arrSize;

    //Receive generated public key from the Server
    arrSize = fromServ.readInt();
    byte[] otherPk = new byte[arrSize];
    fromServ.read(otherPk);
    System.out.println("recived server PK!");

    //Send the server our public key 
    out.writeInt(ourPkLength);
    out.write(ourPk);
    System.out.println("sent PK!");

    KeyFactory kf = KeyFactory.getInstance("EC");
    X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
    PublicKey otherPublicKey = kf.generatePublic(pkSpec);

    //Perform key agreement 
    KeyAgreement ka = KeyAgreement.getInstance("ECDH");
    ka.init(kp.getPrivate());
    ka.doPhase(otherPublicKey, true);

    // Generate a shared secret
    byte[] sharedSecret = ka.generateSecret();

    // Derive a key from the shared secret and both public keys
    MessageDigest hash = MessageDigest.getInstance("SHA-256");
    hash.update(sharedSecret);
    // Simple deterministic ordering
    List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
    Collections.sort(keys);
    hash.update(keys.get(0));
    hash.update(keys.get(1));

    byte[] derivedKey = hash.digest();   
    System.out.println("derived key: " + derivedKey + "  length: " + derivedKey.length);

    //Convert the derivedkey from a byte array to a Secret key Spec of type AES
    SecretKeySpec secretKey = new SecretKeySpec(derivedKey, 0, 32, "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new byte[16]));
    String plainText = "Testing!";
    byte[] cipherText = cipher.doFinal(plainText.getBytes());
    System.out.println("Encrypted str: " + cipherText + "    length: "+ cipherText.length);

    //Send encrypted string to Server
    int len = cipherText.length;
    System.out.println("length: " + len);
    out.write(len);
    out.write(cipherText);
    System.out.println("Sent encrypted string!");
ffvjumwh

ffvjumwh1#

在你的客户中,你写道: out.write(len) . 您的代码片段没有解释 out 是的,但我猜 .write(someIntValue) 是从 java.io.OutputStream 哪个有那个方法( .write(int) ). 问题是,它只写一个字节,去掉int中除底部8以外的所有位。
服务器代码中的匹配调用是: arrSize = fromClient.readInt(); 这不是一个 InputStream 有(我猜你有一些类扩展了inputstream并添加了这些),大概,什么 readInt 读取4个字节,并将它们重新组合成一个java int 假设大端序。
因此,从客户端发送1个字节,然后发送字符串,但服务器将读取4个字节的长度:1个字节(客户端发送的实际长度)加上字符串的前3个字节,并尝试将其解释为一个长度,从而导致不同的数。
276032497是一个数字,如果通过big-endian排序放入字节,则以值为16的字节开始,这正是您发送的长度,这一事实强烈暗示这是您的问题。
修复似乎相当琐碎;转弯 out.write(len) 进入 out.writeInt(len) . 如果你要做这样的字节级协议,你需要一个更好的测试和调试计划¯_(ツ)_/¯ 我想我会问你的。这可能就是为什么大多数人使用不同的解决方案来处理原始字节协议的原因(所以,调查protobuf和朋友)。至少,让实际的管道成为一个可插入的概念,这样你就可以插入一个不加密任何东西的虚拟管道,这样你就可以通过观察传输线上的字节来发现这样的问题;这不太可能是最后一次服务器和客户端的代码不匹配。

相关问题