繁体   English   中英

为什么我的 Java 套接字接收的数组大小比发送的大?

[英]Why is my Java socket receiving an array size larger than what was sent?

我正在创建一个客户端/服务器程序来使用 256 位 AES 执行加密。 我从 ECDH 派生我的密钥。 我发送我用来表示我的各种键和字符串的字节 arrays 的大小。 我遇到的问题是,当我尝试将我的加密字符串的大小从我的客户端发送到我的服务器时,我的服务器说我发送的大小比我实际发送的要大得多。 发送大小适用于需要发送的所有其他字节 arrays。 客户端发送的加密字符串大小为 16 字节。 服务器收到一个大小为 276032497 字节的 integer。 我检查过我实际上是从客户端发送 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!");
    

在您的客户中,您写道: out.write(len) 您的代码片段没有解释out是什么,但我猜.write(someIntValue)是来自java.io.OutputStream的传递,它具有该方法( .write(int) )。 问题是,这会写入一个 byte ,删除 int 中的所有位,除了底部的 8 位。

服务器代码中的匹配调用是:

arrSize = fromClient.readInt();

不是InputStream的调用(我猜你有一些 class 扩展 InputStream 并添加这些),大概是readInt所做的,读取4个字节,并通过假设 Big Endian 排序将它们重组为单个 java int

因此,您从客户端发送 1 个字节,然后是字符串,但服务器将读取 4 个字节的长度:该 1 个字节(客户端发送的实际长度)加上字符串的前 3 个,并尝试解释作为一个长度,导致数字大相径庭

276032497 是一个数字这一事实,如果通过大端顺序放入字节,则以一个值为 16 的字节开头,这正是您发送的长度,强烈暗示这是您的问题。

修复似乎相当微不足道。 out.write(len)变成out.writeInt(len) 而且如果你要做这样的字节级协议,你需要一个比¯\_(ツ)_/¯ 更好的测试和调试计划,我想我会问 StackOverflow。 这可能就是为什么大多数人使用不同的解决方案来处理原始字节协议(所以,调查一下 ProtoBuf 和朋友)。 至少,让实际的 pipe 成为一个可插拔的概念,这样您就可以插入一个不加密任何东西的虚拟 pipe,这样您就可以通过网络传输的字节来查找此类问题; 这不太可能是您最后一次不匹配服务器和客户端的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM