如何使用系統authorized_keys
文件中的條目實現java.security.PublicKey
?我特別希望將authorized_keys文件中的公鑰與Apache SSHD PublickeyAuthenticator
接口中提供的公鑰進行比較。使用Java安全性授權密鑰中的公鑰
回答
我很驚訝這裏沒有任何明顯的表現。我很好奇並實施了一種解碼authorized_keys
文件的方法。這取決於Apache Commons Codec for Base64解碼。
import java.io.File;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Scanner;
import org.apache.commons.codec.binary.Base64;
public class AuthorizedKeysDecoder {
private byte[] bytes;
private int pos;
public PublicKey decodePublicKey(String keyLine) throws Exception {
bytes = null;
pos = 0;
// look for the Base64 encoded part of the line to decode
// both ssh-rsa and ssh-dss begin with "AAAA" due to the length bytes
for (String part : keyLine.split(" ")) {
if (part.startsWith("AAAA")) {
bytes = Base64.decodeBase64(part);
break;
}
}
if (bytes == null) {
throw new IllegalArgumentException("no Base64 part to decode");
}
String type = decodeType();
if (type.equals("ssh-rsa")) {
BigInteger e = decodeBigInt();
BigInteger m = decodeBigInt();
RSAPublicKeySpec spec = new RSAPublicKeySpec(m, e);
return KeyFactory.getInstance("RSA").generatePublic(spec);
} else if (type.equals("ssh-dss")) {
BigInteger p = decodeBigInt();
BigInteger q = decodeBigInt();
BigInteger g = decodeBigInt();
BigInteger y = decodeBigInt();
DSAPublicKeySpec spec = new DSAPublicKeySpec(y, p, q, g);
return KeyFactory.getInstance("DSA").generatePublic(spec);
} else {
throw new IllegalArgumentException("unknown type " + type);
}
}
private String decodeType() {
int len = decodeInt();
String type = new String(bytes, pos, len);
pos += len;
return type;
}
private int decodeInt() {
return ((bytes[pos++] & 0xFF) << 24) | ((bytes[pos++] & 0xFF) << 16)
| ((bytes[pos++] & 0xFF) << 8) | (bytes[pos++] & 0xFF);
}
private BigInteger decodeBigInt() {
int len = decodeInt();
byte[] bigIntBytes = new byte[len];
System.arraycopy(bytes, pos, bigIntBytes, 0, len);
pos += len;
return new BigInteger(bigIntBytes);
}
public static void main(String[] args) throws Exception {
AuthorizedKeysDecoder decoder = new AuthorizedKeysDecoder();
File file = new File("authorized_keys");
Scanner scanner = new Scanner(file).useDelimiter("\n");
while (scanner.hasNext()) {
System.out.println(decoder.decodePublicKey(scanner.next()));
}
scanner.close();
}
}
沒有必要只爲此添加公共庫作爲依賴項。看看DatatypeConverter#parseBase64Binary http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/DatatypeConverter.html#parseBase64Binary(java.lang.String) – LanguagesNamedAfterCofee 2012-09-13 21:32:02
謝謝,男人!爲我節省了數小時的工作時間。 – 2013-01-27 00:37:22
如果可能,會給5 ups!非常感謝! – Daniel 2014-01-14 07:09:05
要WhiteFang34,
你的代碼是真棒,對我太有用,但它有一個微小的錯誤。 Base64.decodeBase64方法只接收字節數組。所以我就這樣修復了。
for (String part : keyLine.split(" ")) {
if (part.startsWith("AAAA")) {
byte [] bytePart = part.getBytes();
bytes = Base64.decodeBase64(bytePart);
break;
}
}
無論如何,感謝您編寫代碼。我希望你能將這段代碼上傳到github或其他地方,或者讓我上傳到我的github回購站。
它看起來取決於你使用的是哪個'Base64'類。 Commons Codec 1.4及更高版本中包含的一個包含我使用的方法:['decodeBase64(java.lang.String)'](http://commons.apache.org/codec/api-release/org/apache/commons/ codec/binary/Base64.html#decodeBase64(java.lang.String)) – WhiteFang34 2012-06-12 06:46:46
如果想逆轉這一過程,即編碼PublicKey
Java對象到Linux authorized_keys
輸入格式,可以使用此代碼:
/**
* Encode PublicKey (DSA or RSA encoded) to authorized_keys like string
*
* @param publicKey DSA or RSA encoded
* @param user username for output authorized_keys like string
* @return authorized_keys like string
* @throws IOException
*/
public static String encodePublicKey(PublicKey publicKey, String user)
throws IOException {
String publicKeyEncoded;
if(publicKey.getAlgorithm().equals("RSA")){
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
ByteArrayOutputStream byteOs = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(byteOs);
dos.writeInt("ssh-rsa".getBytes().length);
dos.write("ssh-rsa".getBytes());
dos.writeInt(rsaPublicKey.getPublicExponent().toByteArray().length);
dos.write(rsaPublicKey.getPublicExponent().toByteArray());
dos.writeInt(rsaPublicKey.getModulus().toByteArray().length);
dos.write(rsaPublicKey.getModulus().toByteArray());
publicKeyEncoded = new String(
Base64.encodeBase64(byteOs.toByteArray()));
return "ssh-rsa " + publicKeyEncoded + " " + user;
}
else if(publicKey.getAlgorithm().equals("DSA")){
DSAPublicKey dsaPublicKey = (DSAPublicKey) publicKey;
DSAParams dsaParams = dsaPublicKey.getParams();
ByteArrayOutputStream byteOs = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(byteOs);
dos.writeInt("ssh-dss".getBytes().length);
dos.write("ssh-dss".getBytes());
dos.writeInt(dsaParams.getP().toByteArray().length);
dos.write(dsaParams.getP().toByteArray());
dos.writeInt(dsaParams.getQ().toByteArray().length);
dos.write(dsaParams.getQ().toByteArray());
dos.writeInt(dsaParams.getG().toByteArray().length);
dos.write(dsaParams.getG().toByteArray());
dos.writeInt(dsaPublicKey.getY().toByteArray().length);
dos.write(dsaPublicKey.getY().toByteArray());
publicKeyEncoded = new String(
Base64.encodeBase64(byteOs.toByteArray()));
return "ssh-dss " + publicKeyEncoded + " " + user;
}
else{
throw new IllegalArgumentException(
"Unknown public key encoding: " + publicKey.getAlgorithm());
}
}
同樣的解決方案,但代表們decodeInt()到DataInputStream類。 只要已經知道RSA算法,我就從原始代碼中刪除KeyFactory的BouncyCastleProvider。
private static RSAPublicKey readKey(String key) throws Exception {
// key = "ssh-rsa <myBase64key> <email>"
byte[] encKey = Base64.decodeBase64(key.split(" ")[1]);
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(encKey));
byte[] header = readElement(dis);
String pubKeyFormat = new String(header);
if (!pubKeyFormat.equals("ssh-rsa"))
throw new RuntimeException("Unsupported format");
byte[] publicExponent = readElement(dis);
byte[] modulus = readElement(dis);
KeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(publicExponent));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(spec);
return pubKey;
}
private static byte[] readElement(DataInput dis) throws IOException {
int len = dis.readInt();
byte[] buf = new byte[len];
dis.readFully(buf);
return buf;
}
謝謝!經過幾個小時的反擊之後,你的代碼對我來說是有意義的,並且解決了這個問題! 'readElement'方法的好主意。 – CullenJ 2017-05-02 22:46:11
- 1. 連接到MQ使用安全密鑰(公鑰和私鑰)
- 2. gitosis授權密鑰
- 3. 從ECDSA公共密鑰創建授權密鑰
- 4. 帶有半私密密鑰的OAuth授權代碼的安全
- 5. Ansible授權密鑰模塊無法讀取公鑰
- 6. 使用Java中的RSA公鑰文件加密AES密鑰
- 7. JavaScript中的API密鑰安全性?
- 8. 用戶的SSH密鑰授權
- 9. SSH公鑰授權不起作用
- 10. 使用DPAPI安全加密密鑰
- 11. 當授權密鑰是我的服務器密鑰時Firebase MismatchSenderID
- 12. 使用公鑰的Java RSA加密
- 13. 安卓硬件支持的密鑰庫中的公鑰有多安全?
- 14. 多個用戶編輯授權密鑰
- 15. 帶有隨機密鑰的公共S3對象的安全性
- 16. PyCrypto:解密只用文件中的公鑰(無私鑰+公鑰)
- 17. 在java中使用RSA公鑰設置密鑰
- 18. 使用RSA公鑰加密DSA私鑰
- 19. Java密鑰和密碼的安全性智能卡在Windows
- 20. 使用密鑰授權創建模型屬性
- 21. ansible - 將密鑰複製到授權密鑰文件
- 22. SSL和公鑰安全
- 23. c#的RSA公共密鑰的公鑰#
- 24. 如何安全使用API密鑰
- 25. 邀請使用安全密鑰
- 26. 使用Spring Redis密鑰安全嗎?
- 27. 加密使用公鑰
- 28. 使用公鑰解密
- 29. Gpg使用公鑰加密
- 30. RSA使用公鑰加密
你也可能要問這個米娜郵件列表上。這是一個非常好的問題,因爲這是安全的Java sshd實現中少數缺失的組件之一。 – 2010-08-20 13:59:00