- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 PKCS#5 加密的 PKCS#8 RSA 私钥存储在一个磁盘文件中(最初由 SSLPlus 生成,大约在 1997 年),例如:
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICmDAaBgkqhkiG9w0BBQMwDQQIybM2XFqx4EwCAQUEggJ4MKg/NE+L6NJgbOf4
...
8QnGu4R7lFlweH/VAK8n0L75h3q2g62MKLJqmKLtAILNve4zymnO+LVZ4Js=
-----END ENCRYPTED PRIVATE KEY-----
为此,我需要获取一个 Java Key 对象,然后我可以将其与匹配的证书一起添加到 KeyStore。私钥使用 100 字节的二进制 key 进行加密。
证书对象的创建很简单,但我似乎无法弄清楚如何从上面的 Base64 编码 PKCS#5 key 到解密的 PKCS#8 RSA 私钥。此时我陷入困境,因为 SecretKeyFactory.generateSecret() 调用失败并显示:
InvalidKeySpecException: Password is not ASCII
现在,密码确实不是 ASCII,严格意义上是 0x00 到 0x7F,但是 PBEWithMD5AndDES 算法应该接受从 0x00 到 0xFF 的字符值。
任何人都可以告诉我如何从 Base64 编码值获取我可以添加到 keystore 的 key 对象吗?
结论
Java 发布的 PBEKey 仅接受 ASCII 值在 0x20<=char<=0x7E 范围内的密码。通过制作我自己的 BinaryPBEKey 解决了我的非 ASCII 密码的问题,它允许从 0x00 到 0xFF 的字节值(见下文)。
我遇到的后续问题是我的 PKCS#8 数据未正确编码(显然是 SSL 早期实现的常见错误),因为 PKCS#1 数据需要包装在 ASN.1 八位字节字符串中。我编写了一个简单的修补例程来处理我的 key ,这些 key 的长度已知在 512 到 4096 位之间(见下文)。
私钥解码器
private PrivateKey readPrivateKey(File inpfil) throws IOException, GeneralSecurityException {
String[] pbeb64s; // PBE ASN.1 data base-64 encoded
byte[] pbedta; // PBE ASN.1 data in bytes
EncryptedPrivateKeyInfo pbeinf; // PBE key info
PBEParameterSpec pbeprm; // PBE parameters
Cipher pbecph; // PBE decryption cipher
byte[] pk8dta; // PKCS#8 ASN.1 data in bytes
KeyFactory pk8fac=KeyFactory.getInstance("RSA"); // PKCS#8 key factory for decoding private key from ASN.1 data.
pbeb64s=readDataBlocks(inpfil,"ENCRYPTED PRIVATE KEY");
if(pbeb64s.length!=1) { throw new GeneralSecurityException("The keystore '"+inpfil+"' contains multiple private keys"); }
pbedta=base64.decode(pbeb64s[0]);
log.diagln(" - Read private key data");
pbeinf=new EncryptedPrivateKeyInfo(pbedta);
pbeprm=(PBEParameterSpec)pbeinf.getAlgParameters().getParameterSpec(PBEParameterSpec.class);
pbecph=Cipher.getInstance(pbeinf.getAlgName());
pbecph.init(Cipher.DECRYPT_MODE,pbeDecryptKey,pbeprm);
pk8dta=pbecph.doFinal(pbeinf.getEncryptedData());
log.diagln(" - Private Key: Algorithm= "+pbeinf.getAlgName()+", Iterations: "+pbeprm.getIterationCount()+", Salt: "+Base16.toString(pbeprm.getSalt()));
pk8dta=patchKeyData(inpfil,pk8dta);
return pk8fac.generatePrivate(new PKCS8EncodedKeySpec(pk8dta));
}
二进制PBE key
import java.io.*;
import java.security.*;
import java.security.spec.*;
import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*;
class BinaryPBEKey
extends Object
implements SecretKey
{
private final byte[] key;
/**
* Creates a PBE key from a given binary key.
*
* @param key The key.
*/
BinaryPBEKey(byte[] key) throws InvalidKeySpecException {
if(key==null) { this.key=new byte[0]; }
else { this.key=(byte[])key.clone(); }
Arrays.fill(key,(byte)0);
}
public byte[] getEncoded() {
return (byte[])key.clone();
}
public String getAlgorithm() {
return "PBEWithMD5AndDES";
}
public String getFormat() {
return "RAW";
}
/**
* Calculates a hash code value for the object.
* Objects that are equal will also have the same hashcode.
*/
public int hashCode() {
int ret=0;
for(int xa=1; xa<this.key.length; xa++) { ret+=(this.key[xa]*xa); }
return (ret^=getAlgorithm().toLowerCase().hashCode());
}
public boolean equals(Object obj) {
if(obj==this ) { return true; }
if(obj.getClass()!=getClass()) { return false; }
BinaryPBEKey oth=(BinaryPBEKey)obj;
if(!(oth.getAlgorithm().equalsIgnoreCase(getAlgorithm()))) {
return false;
}
byte[] othkey=oth.getEncoded();
boolean ret =Arrays.equals(key,othkey);
Arrays.fill(othkey,(byte)0);
return ret;
}
public void destroy() {
Arrays.fill(this.key,(byte)0);
}
/**
* Ensure that the password bytes of this key are zeroed out when there are no more references to it.
*/
protected void finalize() throws Throwable {
try { destroy(); } finally { super.finalize(); }
}
PKCS#8 补丁
/**
* Patch the private key ASN.1 data to conform to PKCS#8.
* <p>
* The SSLPlus private key is not properly encoded PKCS#8 - the PKCS#1 RSAPrivateKey should have been wrapped
* inside an OctetString, thus:
* <pre>
* SSLPlus Encoding:
* 0 30 627: SEQUENCE {
* 4 02 1: INTEGER 0
* 7 30 13: SEQUENCE {
* 9 06 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
* 20 05 0: NULL
* : }
* 22 30 605: SEQUENCE {
* 26 02 1: INTEGER 0
* 29 02 129: INTEGER
* : 00 CA 72 B8 D1 B8 8E B9 39 C0 92 C1 4C 53 B4 F4
* ...
*
* PKCS#8 Encoding
* 0 30 631: SEQUENCE {
* 4 02 1: INTEGER 0
* 7 30 13: SEQUENCE {
* 9 06 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
* 20 05 0: NULL
* : }
* ==> 22 04 609: OCTET STRING, encapsulates {
* 26 30 605: SEQUENCE {
* 30 02 1: INTEGER 0
* 33 02 129: INTEGER
* : 00 CA 72 B8 D1 B8 8E B9 39 C0 92 C1 4C 53 B4 F4
* ...
* </pre>
*
* Hex Dumps (1K key, space padded for clarity):
* Before : 30 820271 020100300D06092A864886F70D0101010500 30 82025B ... A228
* After : 30 820275 020100300D06092A864886F70D0101010500 04 82025F 30 82025B ... A228
* ^^^^^^ ^^^^^^
* Add 4 for later 0482xxxx Original total + 4 - 22 (equals the key length of 025B+4)
*/
private byte[] patchKeyData(File inpfil, byte[] asndta) throws IOException, GeneralSecurityException { // except it really doesn't throw an exception
ByteArrayOutputStream patdta=new ByteArrayOutputStream();
int orglen=decodeAsnLength(inpfil,asndta,1);
patdta.write(asndta,0,1); // original leader type
patdta.write(encodeAsnLength(inpfil,(orglen+4))); // new total length
patdta.write(asndta,4,(22-4)); // bit between total length an where octet-string wrapper needs to be inserted
patdta.write(0x04); // octet-string type
patdta.write(encodeAsnLength(inpfil,(orglen+4-22))); // octet-string length (key data type+key data length+key data)
patdta.write(asndta,22,asndta.length-22); // private key data
return patdta.toByteArray();
}
private int decodeAsnLength(File inpfil, byte[] asndta, int ofs) throws GeneralSecurityException {
if((asndta[ofs]&0xFF)==0x82) { return (((asndta[ofs+1]&0x000000FF)<< 8)|((asndta[ofs+2]&0x000000FF))); }
else { throw new GeneralSecurityException("The private key in file '"+inpfil+"' is not supported (ID="+Base16.toString(asndta,0,4)+")"); }
}
private byte[] encodeAsnLength(File inpfil, int len) throws GeneralSecurityException {
if(len>=0x0100 && len<=0xFFFF) { return new byte[]{ (byte)0x82,(byte)((len>>>8)&0x000000FF),(byte)len }; }
else { throw new GeneralSecurityException("The new length of "+len+" for patching the private key in file '"+inpfil+"' is out of range"); }
}
最佳答案
我刚刚将您的解密数据转储到 ASN.1 解析器中,对我来说它看起来像完美的 ASN.1:
0 30 627: SEQUENCE {
4 02 1: INTEGER 0
7 30 13: SEQUENCE {
9 06 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
20 05 0: NULL
: }
22 30 605: SEQUENCE {
26 02 1: INTEGER 0
29 02 129: INTEGER
: 00 CA 72 B8 D1 B8 8E B9 39 C0 92 C1 4C 53 B4 F4
: 38 48 3F C3 1C DC 6B BC BE 26 A3 B2 F7 7C 60 A8
: 2C 0D 86 ED FC 2D D2 5C 99 B6 B6 71 A8 6D 2F 51
: 25 FA 9C 42 FE 10 C1 2F 39 EA E8 FF 1A 78 BA 6B
: 64 B8 39 34 3B F4 1C 45 06 C3 B9 98 DC 01 FF 41
: 56 36 4F DD 35 69 A4 27 BB 5F FD DD 5C 73 BA 9A
: 94 5A 4F 37 A9 48 3D 5B 89 EA EE BA 8D 02 6E D7
: 6E D4 6F BC 7D 7A A4 41 4C 4D CA 08 05 20 66 A3
: [ Another 1 bytes skipped ]
161 02 3: INTEGER 65537
166 02 128: INTEGER
: 21 6A E2 7B 2B DD D3 51 67 2A 52 62 09 07 3B B0
: F6 AC 1F C6 E9 D3 96 EA 44 72 8D 1E 31 17 BB 6A
: DA 28 C5 AB F4 DC 5E 90 B9 0A 50 A4 9E B1 4A D1
: DC 16 63 30 91 0F 72 7E 3A FA 8E F1 8D B0 27 FD
: C2 BA B5 F8 FC 7C 46 C0 FD AD A7 39 7C 36 71 7A
: 33 8B AD 0D 0C DA 50 B7 0E BF D8 64 7D 44 BD 64
: 6F E2 51 B7 5E 2D 7B BA 02 DB A6 2F 20 88 66 98
: 85 34 2E EF D4 29 61 23 79 87 27 27 55 15 8D 21
297 02 65: INTEGER
: 00 F9 62 BD 22 4A C8 56 7A C3 17 EB CE CC 5F 42
: E1 40 F5 A5 66 60 32 54 86 67 26 AD 7C 34 C2 FE
: FE 8A F7 7F BE 79 53 5F C9 73 D9 47 8B 0F 89 A1
: 09 F1 27 16 FC F1 4B C3 A9 27 59 29 0D DA 9C AE
: 53
364 02 65: INTEGER
: 00 CF D1 4A 31 50 9A B4 BA 90 42 25 49 54 7C 20
: 54 2E CF E8 F1 35 DA 92 C2 A3 94 9D B7 B1 85 3F
: 13 D0 CA BC 77 D9 8A F3 32 83 59 93 E1 F0 11 1B
: 4C E5 A2 30 50 FE 1F B6 8D A5 B1 44 DA 4D 4B 11
: 09
431 02 64: INTEGER
: 46 53 3A C4 9D D4 0A D7 09 87 08 5F 43 B0 A5 5A
: 82 08 03 81 70 25 21 42 D9 79 C5 B8 5D E4 93 25
: D2 A8 62 A4 A2 F0 08 F5 F5 2E 53 87 7A 75 34 2D
: 6A 8C BC 65 CD E1 B0 A6 55 CB 45 D1 7B 51 6D B3
497 02 65: INTEGER
: 00 81 CC 61 7F 9D AD 92 F5 F7 86 28 CD BD 43 ED
: D9 46 87 BB 21 75 16 78 95 B3 1F EE C6 3D CD 50
: 91 6A D6 45 92 C1 C0 24 97 C7 2C 5A CE 42 68 1C
: DA 11 8F 14 88 71 C0 92 FF B3 9E 9D B7 8F 91 34
: 29
564 02 65: INTEGER
: 00 88 7A 99 AC AA A9 D5 2B 6E E1 87 0A E8 D2 4C
: 04 8E A2 EA 00 3F 8D AF 9F 76 61 86 B0 1D 18 69
: C8 64 22 D4 6B A3 A4 BB 52 B1 AC 38 DB 6B 5C 28
: F0 78 73 3E 37 FD C8 54 72 C7 FD A9 EB C9 F2 45
: 96
: }
: }
不幸的是,它不是正确编码的 PKCS#8 PrivateKeyInfo。从索引 22 开始的序列是一个 PKCS#1 PKCS1RSAPrivateKey,它应该被包装在一个 OctetString 中,以便正确编码结构。
试试这个: 30820277020100300D06092A864886F70D0101010500048202613082025D02010002818100CA72B8D1B88EB939C092C14C53B4F438483FC31CDC6BBCBE26A3B2F77C60A82C0D86EDFC2DD25C99B6B671A86D2F5125FA9C42FE10C12F39EAE8FF1A78BA6B64B839343BF41C4506C3B998DC01FF4156364FDD3569A427BB5FFDDD5C73BA9A945A4F37A9483D5B89EAEEBA8D026ED76ED46FBC7D7AA4414C4DCA08052066A3EB0203010001028180216AE27B2BDDD351672A526209073BB0F6AC1FC6E9D396EA44728D1E3117BB6ADA28C5ABF4DC5E90B90A50A49EB14AD1DC166330910F727E3AFA8EF18DB027FDC2BAB5F8FC7C46C0FDADA7397C36717A338BAD0D0CDA50B70EBFD8647D44BD646FE251B75E2D7BBA02DBA62F2088669885342EEFD42961237987272755158D21024100F962BD224AC8567AC317EBCECC5F42E140F5A566603254866726AD7C34C2FEFE8AF77FBE79535FC973D9478B0F89A109F12716FCF14BC3A92759290DDA9CAE53024100CFD14A31509AB4BA90422549547C20542ECFE8F135DA92C2A3949DB7B1853F13D0CABC77D98AF332835993E1F0111B4CE5A23050FE1FB68DA5B144DA4D4B1109024046533AC49DD40AD70987085F43B0A55A8208038170252142D979C5B85DE49325D2A862A4A2F008F5F52E53877A75342D6A8CBC65CDE1B0A655CB45D17B516DB302410081CC617F9DAD92F5F78628CDBD43EDD94687BB2175167895B31FEEC63DCD50916AD64592C1C02497C72C5ACE42681CDA118F148871C092FFB39E9DB78F913429024100887A99ACAAA9D52B6EE1870AE8D24C048EA2EA003F8DAF9F766186B01D1869C86422D46BA3A4BB52B1AC38DB6B5C28F078733E37FDC85472C7FDA9EBC9F24596
解析:
0 30 631: SEQUENCE {
4 02 1: INTEGER 0
7 30 13: SEQUENCE {
9 06 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
20 05 0: NULL
: }
22 04 609: OCTET STRING, encapsulates {
26 30 605: SEQUENCE {
30 02 1: INTEGER 0
33 02 129: INTEGER
: 00 CA 72 B8 D1 B8 8E B9 39 C0 92 C1 4C 53 B4 F4
: 38 48 3F C3 1C DC 6B BC BE 26 A3 B2 F7 7C 60 A8
: 2C 0D 86 ED FC 2D D2 5C 99 B6 B6 71 A8 6D 2F 51
: 25 FA 9C 42 FE 10 C1 2F 39 EA E8 FF 1A 78 BA 6B
: 64 B8 39 34 3B F4 1C 45 06 C3 B9 98 DC 01 FF 41
: 56 36 4F DD 35 69 A4 27 BB 5F FD DD 5C 73 BA 9A
: 94 5A 4F 37 A9 48 3D 5B 89 EA EE BA 8D 02 6E D7
: 6E D4 6F BC 7D 7A A4 41 4C 4D CA 08 05 20 66 A3
: [ Another 1 bytes skipped ]
165 02 3: INTEGER 65537
170 02 128: INTEGER
: 21 6A E2 7B 2B DD D3 51 67 2A 52 62 09 07 3B B0
: F6 AC 1F C6 E9 D3 96 EA 44 72 8D 1E 31 17 BB 6A
: DA 28 C5 AB F4 DC 5E 90 B9 0A 50 A4 9E B1 4A D1
: DC 16 63 30 91 0F 72 7E 3A FA 8E F1 8D B0 27 FD
: C2 BA B5 F8 FC 7C 46 C0 FD AD A7 39 7C 36 71 7A
: 33 8B AD 0D 0C DA 50 B7 0E BF D8 64 7D 44 BD 64
: 6F E2 51 B7 5E 2D 7B BA 02 DB A6 2F 20 88 66 98
: 85 34 2E EF D4 29 61 23 79 87 27 27 55 15 8D 21
301 02 65: INTEGER
: 00 F9 62 BD 22 4A C8 56 7A C3 17 EB CE CC 5F 42
: E1 40 F5 A5 66 60 32 54 86 67 26 AD 7C 34 C2 FE
: FE 8A F7 7F BE 79 53 5F C9 73 D9 47 8B 0F 89 A1
: 09 F1 27 16 FC F1 4B C3 A9 27 59 29 0D DA 9C AE
: 53
368 02 65: INTEGER
: 00 CF D1 4A 31 50 9A B4 BA 90 42 25 49 54 7C 20
: 54 2E CF E8 F1 35 DA 92 C2 A3 94 9D B7 B1 85 3F
: 13 D0 CA BC 77 D9 8A F3 32 83 59 93 E1 F0 11 1B
: 4C E5 A2 30 50 FE 1F B6 8D A5 B1 44 DA 4D 4B 11
: 09
435 02 64: INTEGER
: 46 53 3A C4 9D D4 0A D7 09 87 08 5F 43 B0 A5 5A
: 82 08 03 81 70 25 21 42 D9 79 C5 B8 5D E4 93 25
: D2 A8 62 A4 A2 F0 08 F5 F5 2E 53 87 7A 75 34 2D
: 6A 8C BC 65 CD E1 B0 A6 55 CB 45 D1 7B 51 6D B3
501 02 65: INTEGER
: 00 81 CC 61 7F 9D AD 92 F5 F7 86 28 CD BD 43 ED
: D9 46 87 BB 21 75 16 78 95 B3 1F EE C6 3D CD 50
: 91 6A D6 45 92 C1 C0 24 97 C7 2C 5A CE 42 68 1C
: DA 11 8F 14 88 71 C0 92 FF B3 9E 9D B7 8F 91 34
: 29
568 02 65: INTEGER
: 00 88 7A 99 AC AA A9 D5 2B 6E E1 87 0A E8 D2 4C
: 04 8E A2 EA 00 3F 8D AF 9F 76 61 86 B0 1D 18 69
: C8 64 22 D4 6B A3 A4 BB 52 B1 AC 38 DB 6B 5C 28
: F0 78 73 3E 37 FD C8 54 72 C7 FD A9 EB C9 F2 45
: 96
: }
: }
: }
要修复您的文件,您可以使用 ASN.1 库(但我不知道有什么适合 Java 的库),或者执行以下操作:
检查您的数据是否以 30(*1)020100300D06092A864886F70D010101050030(*2)
(*1)
和(*2)
将是以下形式之一的长度编码
XX
,其中XX是长度81XX
,其中XX是长度82XXXX
,其中 XXXX 是长度83XXXXXX
,其中 XXXXXX 是长度等如果您的 key 长度都相同,您可能会假设长度编码始终采用 82XXXX
形式,但实际长度可能会有所不同。
读取(*2)
中的长度,将30(*2)
的字节长度加到数字上(这大概是4),对长度进行编码如上(很可能是 82XXXX
的形式)。我们称此长度编码为 (*3)
。在 30(*2)
之前插入 04(*3)
。现在将 04(*3)
的长度(可能也是 4)添加到 (*1)
并重新编码(可能仍然适合 82XXXX
) 并用此替换 (*1)
。
我希望这是可以理解的,否则我建议阅读 A Layman's Guide to a Subset of ASN.1, BER, and DER .
关于java - 如何在 Java 中解码 PKCS#5 加密的 PKCS#8 私钥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/809590/
我有以下 json: {"results": [{"columns":["room_id","player_name","player_ip"], "types":["integer","text
我在 go 中获取格式不一致的 JSON 文件。例如,我可以有以下内容: {"email": "\"blah.blah@blah.com\""} {"email": "robert@gmail.com
JavaScript中有JSON编码/解码base64编码/解码函数吗? 最佳答案 是的,btoa() 和 atob() 在某些浏览器中可以工作: var enc = btoa("this is so
我在其中一个项目中使用了 Encog,但在解码 One-Of Class 时卡住了。该字段的规范化操作之一是 NormalizationAction.OneOf,它具有三个输出。当我评估时,我想解码预
在我的 previous question关于使用 serialize() 创建对象的 CSV 我从 jmoy 那里得到了一个很好的答案,他推荐了我的序列化文本的 base64 编码。这正是我要找的。
有些事情让我感到困惑 - 为什么 this image在每个浏览器中显示不同? IE9(和 Windows 照片查看器)中的图像: Firefox(和 Photoshop)中的图像: Chrome(和
是否可以在不知道它的类型( JAXBContext.newInstance(clazz) )的情况下解码一个类,或者什么是测试即将到来的正确方法? 我确实收到了从纯文本中解码的消息 - 字符串 传入的
我正在尝试使用 openSSL 库进行 Base64 解码,然后使用 CMS 来验证签名。 下面的代码总是将缓冲区打印为 NULL。 char signed_data[] = "MIIO"; int
我有一个带有 SEL 类型实例变量的类,它是对选择器的引用。在encodeWithCoder/initWithCoder中,如何编码/解码这种类型的变量? 最佳答案 您可以使用 NSStringFro
var url = 'http://www.googleapis.com/customsearch/v1?q=foo&searchType=image'; window.fetch(url) .t
我想知道Android 2.2、2.3和3,4支持的音频/视频格式列表。我也想知道哪些Android版本支持视频编码和解码。我经历了this link,但是关于编码和解码我并不清楚。 任何人的回答都是
我在其中一个项目中使用 Encog,但在解码 One-Of 类时遇到了困难。该字段的规范化操作之一是 NormalizationAction.OneOf,它具有三个输出。当我评估时,我想解码预测值。如
我正在尝试解码现有的 xml 文件,以便我可以正确处理数据,但 XML 结构看起来很奇怪。下面是 xml 示例以及我创建的对象。 11 266 AA1001 1
对 unicode 字符进行 URL 编码的常用方法是将其拆分为 2 %HH 代码。 (\u4161 => %41%61) 但是,unicode在解码时是如何区分的呢?您如何知道 %41%61 是 \
我正在尝试将 json 字符串解码为 Map。 我知道有很多这样的问题,但我需要非常具体的格式。例如,我有 json 字符串: { "map": { "a": "b",
我有一个查询,我认为需要像这样(解码会更大) SELECT firstName, lastName, decode(mathMrk, 80, 'A', mathMrk) as decodeMat
我知道PHP函数encode()和decode(),它们对我来说工作得很好,但我想在url中传递编码字符串,但encode确实返回特殊字符,如“=”、“”' “等等...... 这显然会破坏我的脚本,
我必须解码 Basic bW9uTG9naW46bW9uTW90RGVQYXNz 形式的 http 请求的授权 header 当我解码它时online ,我得到了正确的结果 monLogin:monM
这个问题已经有答案了: Decode Base64 data in Java (21 个回答) 已关闭 8 年前。 我想知道使用哪个库进行 Base64 编码/解码?我需要此功能足够稳定以供生产使用。
我正在尝试从 Arduino BT 解码 []byte,我的连接完美,问题是当我尝试解码数组时。我得到的只是这个字符�(发送的字节数相同)我认为问题出在解码上。我尝试使用 ASCII 字符集,但仍然存
我是一名优秀的程序员,十分优秀!