我对密码学有点陌生,一个要求需要我
"创建或检索用户的RSA-OAEP密钥。对于设备,每个用户应该有一个公钥/私钥对"
并以这种形式将其发送到服务器:
{"modulus":"qMBRpdYrAy5aMmo31NErUizh5sbweguSmh4wlK6uJEIDl+kwTlROnE34KOFExeTbJSX0WygPi+vWl0yNq7buIMUKpytossAAWut5khO3CQJxTk7G2gnEPNUUXHiExGgNrLzcSLv8YIlfVALhoRWyC67KOL+a+3taNq3h+BHeWhM=","exponent":"AQAB"}
我尝试使用OpenSSL命令生成RSA公钥/私钥对,结果如下:
公钥(为了安全起见,将值更改了一点):
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4NMwqhswK6Py+N1OlPBn3JelqEdZ8YwSn4j1Kvp5HK+pS/5gcABkx/89buDhhtKvZ8mfSNkhKHU2WuBPIikGAvEKbbbQ8DHKubHa07X1xTgY+qMyxTLaHnaEC6oOi6BixPfo6QAm+SnqxBWuvDPBzGqSS+/p5r7aydLBAlkoZ+DzpBbAHIIK72c+xqCL8oOFz4QqsVMakdKQ+fVdM1e8U2ak4ygHOleqJgcl8+xH7TFJsvUOfsgsMlz2FmNXWhCYUdOKglP8ZUVMuiAW9KEjAFta4xEf3bBGRDYss7mLQF5/RHbpzYeNwQ1RVp8bhTumpQytqJZshUj8DA3oqMFUr xyz@xyz.xyz
私钥(为了安全起见,将值更改了一点):
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,67A126EE3266B641AF4AC698AA18FE01
3w4GI7HfymD0A8+LokUbsIiI50CJfszBjO5PR4tW532ccKVMQRKywBMANUWx5B66
Mkr/uY9lH8mJOhWrwwiXCUFKMtDGcC06NHbIWIAu/TP85TidwhtGABqSYkjh+8Hm
SlwTMe2xjPq+X8Xc8+vW6Ng8mvXST0Ezz4DiTKA9yeH0eVxIQ4WIpvO7X9793xSD
FoXQ5sCY7Mr6GBNxln4f9cy5BwEsEGa86dtzXVkK8Gu8xRy28GE4W7D6/eNkgl6B
ovEuuC7IDibP/qrGAq/Nxdrl6QrnFTd2FcQfbR4jeArC+IaeXAxXgqhhTJH9ySk8
ZnEaMIruEGvRbChwzlvqS/sCMcS8eoD22Di94Gmkv4thSIWuk1MTRMTKFTMAgVOb
8shCKgCR5FJXjPHV8sUhIwk4TrQWX70fWM3QmBq3ue2AnGonWXhzXQU7jB36zATm
dhpsHZ2/80BuB/hMnFJpsjcYU16pm9BunSMs7tyMW3X3F91x6liC3j2ItUjEkPME
P6eZE2KDM+QxlDLfebL+bGMN6rYvEmfvKo44nwNIMnJM9J3ZYNM9KGt87B4loVwn
TeWIGrCQ9SRCpiAVbZj+M9DDDuqxSoA0wxSDrcYjWt8trzS20AWj7lsxBQgUvpBX
nuFAQgMgT4DK9X2z9ESplXi/l2uZ0iDBTN4SEHI3oR3ar2rWSjoQrTTfOg7cYlF1
ewLR6toCEEvturC4vLyWyrDIu3P/jiSz6eiSTeI9W02rQ/qILUrouKx1LwviIKR2
OGQnkzm3iiNq0jykzObwCsDLuY6rA4nv/ZBsjLDWB34gveKSzOrtx4dzqmtcv0Kq
ndua6xdaPmpV3n4slRD1PxSwNgKb4qwlYuQMPKLhCXUq4yG59IOoH7yfxS5UZ7wa
yndGMLMPmylcHDLX02U90X3feUcC9IiE7z6pOILy4uC28Z2X5KYjoK07pwA+5lNt
9RvryaK4IXysJZ5zqsBUaeYlqqBATcEPYn3YXbT5cSaxkv4lI36g6iG7/QmA3PGt
1l57kBW2xnUSrqm5XtZZMrsSu2iZ9Hiuh73SRkODjg7ToEMtwLECkN1TRL9PVEQj
QHAxauWleC+2yB0+1XH7/CywkYk2HxeNQJJDsWU+XJM/RFGFNV481LwfU0Hw58sZ
ai4R2LmDDoy4wwtcQGkY13ZHT8h/jxP4/Sr36GJdVkhhUCDnpFfdNHebgflj0PQg
eTHVY/6GqfnKvneOGtDRR4EkBFopUV5OLzuRX3z/rlHRV1iPCaqhooL9XO320JYq
xY5YMWq7tvgzE5jtqo65AwO8WWs12NTzG1KRhcXCyYE4Da1T6k7l8++MOeVGZy1v
qDxEddTfiAzIvCme2lEiYOb2/UUNAhEM+Ave/lfWmirW5dSAOppZenHUnuZh9eVd
iFVswrAxcd4BqA5GGczzu9EIqdzpspTrnG3hxOf+tXEXf3TTAH/sTVfQGQHO1iRd
UTh9FGgHk3WMswBnYyfpbSOR8Mghab966RRYP2xBCVJEvCymYuUE11x6vsvQFpGS
X2SEhOpzgINuKZRTuVmhK1oXRt3BZO8yQ13t+wtQCP6a8azS+Sc436aDqBlWQfJ2
-----END RSA PRIVATE KEY-----
如何从这些数据中提取服务器期望的模数和指数形式?
您可以简单地从RFC4253中获取格式,但您需要从RFC4251中找出mpint
(多预置整数)格式。
这是Java的事情(Java),仅仅是因为JSch库太可怕了。
package nl.owlstead.crypto;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.Base64.Encoder;
public class SSHPublicKeyDecoder {
private static byte[] SSH_RSA_HEADER = "ssh-rsa".getBytes(StandardCharsets.US_ASCII);
private static RSAPublicKey decodeRSAPublicKey(byte[] encodedRSAPublicKey)
throws NoSuchAlgorithmException, InvalidKeySpecException {
ByteBuffer buf = ByteBuffer.wrap(encodedRSAPublicKey);
byte[] header = getSSHEncodedValueFromBuffer(buf);
if (!Arrays.equals(header, SSH_RSA_HEADER)) {
throw new IllegalArgumentException("Not an RSA public key");
}
byte[] eDataSigned = getSSHEncodedValueFromBuffer(buf);
BigInteger e = new BigInteger(eDataSigned);
byte[] nDataSigned = getSSHEncodedValueFromBuffer(buf);
BigInteger n = new BigInteger(nDataSigned);
KeyFactory rsaKeyFactory;
try {
rsaKeyFactory = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException ex) {
throw new IllegalStateException(
"KeyFactory should exist for RSA", ex);
}
RSAPublicKeySpec spec = new RSAPublicKeySpec(n, e);
return (RSAPublicKey) rsaKeyFactory.generatePublic(spec);
}
private static byte[] getSSHEncodedValueFromBuffer(ByteBuffer buf) {
int size = buf.getInt();
if (size < 0) {
throw new IllegalArgumentException("Bad SSH encoded value in format");
}
byte[] data = new byte[size];
buf.get(data);
return data;
}
private static byte[] toUnsigned(BigInteger value) {
if (value.compareTo(BigInteger.ZERO) <= 0) {
throw new IllegalArgumentException("Negative numbers cannot be encoded as unsigned integers");
}
if (value.equals(BigInteger.ZERO)) {
return value.toByteArray();
}
final byte[] signedBigEndian = value.toByteArray();
if (signedBigEndian[0] == 0x00) {
return Arrays.copyOfRange(signedBigEndian, 1, signedBigEndian.length);
}
return signedBigEndian;
}
private SSHPublicKeyDecoder() {
}
public static void main(String[] args) throws Exception {
String[] parts = args[0].split("\\s+");
String part2 = parts[1];
byte[] encodedRSAPublicKey = Base64.getDecoder().decode(part2);
RSAPublicKey pubKey = decodeRSAPublicKey(encodedRSAPublicKey);
String format = encodeServerPublicKey(pubKey);
System.out.println(format);
}
private static String encodeServerPublicKey(RSAPublicKey pubKey) {
byte[] nData = toUnsigned(pubKey.getModulus());
byte[] eData = toUnsigned(pubKey.getPublicExponent());
Encoder base64Encoder = Base64.getEncoder();
String format = String.format(
"{\"modulus\":\"%s\",\"exponent\":\"%s\"}%n",
base64Encoder.encodeToString(nData),
base64Encoder.encodeToString(eData));
return format;
}
}