📄 ssh2keypairfile.java
字号:
} catch (NoSuchAlgorithmException e) { throw new SSH2FatalException("Invalid cipher in " + "SSH2KeyPairFile.writeKeyPair: " + cipher); } catch (InvalidKeyException e) { throw new SSH2FatalException("Invalid key derived in " + "SSH2KeyPairFile.writeKeyPair: " + e); } } SSH2DataBuffer buf = new SSH2DataBuffer(512 + totLen); buf.writeInt(SSH_PRIVATE_KEY_MAGIC); buf.writeInt(0); // total length (filled in below) buf.writeString("dl-modp{sign{dsa-nist-sha1},dh{plain}}"); buf.writeString(cipher); buf.writeString(toBeEncrypted.getData(), 0, totLen); totLen = buf.getWPos(); buf.setWPos(4); buf.writeInt(totLen); byte[] keyBlob = new byte[totLen]; System.arraycopy(buf.data, 0, keyBlob, 0, totLen); return keyBlob; } public static KeyPair readKeyPair(ASCIIArmour armour, byte[] keyBlob, String password) throws SSH2Exception { String procType = armour.getHeaderField(PRV_PROCTYPE); if(procType != null && password != null) { String dekInfo = armour.getHeaderField(PRV_DEKINFO); if(dekInfo == null || !dekInfo.startsWith("DES-EDE3-CBC,")) { throw new SSH2FatalException("Proc type not supported: " + procType); } dekInfo = dekInfo.substring(13); BigInteger dekI = new BigInteger(dekInfo, 16); byte[] iv = dekI.toByteArray(); if(iv.length > 8) { byte[] tmp = iv; iv = new byte[8]; System.arraycopy(tmp, 1, iv, 0, 8); } doCipher(Cipher.DECRYPT_MODE, password, keyBlob, keyBlob.length, keyBlob, iv); } ByteArrayInputStream enc = new ByteArrayInputStream(keyBlob); ASN1DER der = new ASN1DER(); KeySpec prvSpec = null; KeySpec pubSpec = null; String keyFactType = null; String head = armour.getHeaderLine(); if(head.indexOf("DSA") != -1) { keyFactType = "DSA"; } else if(head.indexOf("RSA") != -1) { keyFactType = "RSA"; } try { if("DSA".equals(keyFactType)) { PEMDSAPrivate dsa = new PEMDSAPrivate(); der.decode(enc, dsa); BigInteger p, q, g, x, y; p = dsa.p.getValue(); q = dsa.q.getValue(); g = dsa.g.getValue(); y = dsa.y.getValue(); x = dsa.x.getValue(); prvSpec = new DSAPrivateKeySpec(x, p, q, g); pubSpec = new DSAPublicKeySpec(y, p, q, g); } else if("RSA".equals(keyFactType)) { RSAPrivateKey rsa = new RSAPrivateKey(); der.decode(enc, rsa); BigInteger n, e, d, p, q, pe, qe, u; n = rsa.modulus.getValue(); e = rsa.publicExponent.getValue(); d = rsa.privateExponent.getValue(); p = rsa.prime1.getValue(); q = rsa.prime2.getValue(); pe = rsa.exponent1.getValue(); qe = rsa.exponent2.getValue(); u = rsa.coefficient.getValue(); prvSpec = new RSAPrivateCrtKeySpec(n, e, d, p, q, pe, qe, u); pubSpec = new RSAPublicKeySpec(n, e); } else { throw new SSH2FatalException("Unsupported key type: " + keyFactType); } } catch (IOException e) { throw new SSH2AccessDeniedException("Invalid password or corrupt key blob"); } try { KeyFactory keyFact = KeyFactory.getInstance(keyFactType); return new KeyPair(keyFact.generatePublic(pubSpec), keyFact.generatePrivate(prvSpec)); } catch (Exception e) { throw new SSH2FatalException("Error in readKeyPair: " + e ); } } public static KeyPair readKeyPairSSHCom(byte[] keyBlob, String password) throws SSH2Exception { SSH2DataBuffer buf = new SSH2DataBuffer(keyBlob.length); buf.writeRaw(keyBlob); int magic = buf.readInt(); int privateKeyLen = buf.readInt(); String type = buf.readJavaString(); String cipher = buf.readJavaString(); int bufLen = buf.readInt(); if(type.indexOf("dl-modp") == -1) { // !!! TODO: keyformaterror exception? throw new SSH2FatalException("Unknown key type '" + type + "'"); } if(magic != SSH_PRIVATE_KEY_MAGIC) { // !!! TODO: keyformaterror exception? throw new SSH2FatalException("Invalid magic in private key: " + magic); } if(!cipher.equals("none")) { try { int keyLen = SSH2Preferences.getCipherKeyLen(cipher); String cipherName = SSH2Preferences.ssh2ToJCECipher(cipher); byte[] key = expandPasswordToKeySSHCom(password, keyLen); Cipher decrypt = Cipher.getInstance(cipherName); decrypt.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, decrypt.getAlgorithm())); byte[] data = buf.getData(); int offset = buf.getRPos(); decrypt.doFinal(data, offset, bufLen, data, offset); } catch (NoSuchAlgorithmException e) { throw new SSH2FatalException("Invalid cipher in " + "SSH2KeyPairFile.readKeyPairSSHCom: " + cipher); } catch (InvalidKeyException e) { throw new SSH2FatalException("Invalid key derived in " + "SSH2KeyPairFile.readKeyPairSSHCom: " + e); } } int parmLen = buf.readInt(); if(parmLen > buf.getMaxReadSize() || parmLen < 0) { throw new SSH2AccessDeniedException("Invalid password or corrupt key blob"); } int value = buf.readInt(); BigInteger p, q, g, x, y; if(value == 0) { p = buf.readBigIntBits(); g = buf.readBigIntBits(); q = buf.readBigIntBits(); y = buf.readBigIntBits(); x = buf.readBigIntBits(); } else { // !!! TODO: predefined params throw new Error("Predefined DSA params not implemented (" + value + ") '" + buf.readJavaString() + "'"); } try { KeyFactory keyFact = KeyFactory.getInstance("DSA"); return new KeyPair(keyFact.generatePublic( new DSAPublicKeySpec(y, p, q, g)), keyFact.generatePrivate( new DSAPrivateKeySpec(x, p, q, g))); } catch (Exception e) { throw new SSH2FatalException( "Error in SSH2KeyPairFile.readKeyPair: " + e ); } } public void store(String fileName, SecureRandom random, String password) throws IOException, SSH2FatalException { store(fileName, random, password, sshComFormat); } public void store(String fileName, SecureRandom random, String password, boolean sshComFormat) throws IOException, SSH2FatalException { armour.setBlankHeaderSep(!sshComFormat); armour.setLineLength(sshComFormat ? ASCIIArmour.DEFAULT_LINE_LENGTH : 64); armour.setHeaderField(PRV_PROCTYPE, null); armour.setHeaderField(PRV_DEKINFO, null); armour.setHeaderField(FILE_SUBJECT, null); armour.setHeaderField(FILE_COMMENT, null); byte[] keyBlob = null; if(sshComFormat) { if(!(keyPair.getPublic() instanceof DSAPublicKey)) { throw new SSH2FatalException( "Only DSA keys supported when saving in compatibility mode"); } String cipher = ((password != null && password.length() > 0) ? "3des-cbc" : "none"); armour.setHeaderLine(BEGIN_PRV_KEY[TYPE_SSHCOM_DSA]); armour.setTailLine(END_PRV_KEY[TYPE_SSHCOM_DSA]); comment = "\"" + comment + "\""; keyBlob = writeKeyPairSSHCom(password, cipher, keyPair); } else { keyBlob = writeKeyPair(armour, password, random, keyPair); } armour.setHeaderField(FILE_SUBJECT, subject); armour.setHeaderField(FILE_COMMENT, comment); FileOutputStream out = new FileOutputStream(fileName); armour.setCanonicalLineEnd(false); armour.encode(out, keyBlob); out.close(); } public void load(String fileName, String password) throws IOException, SSH2Exception { FileInputStream in = new java.io.FileInputStream(fileName); PushbackInputStream pbi = new PushbackInputStream(in); int c = pbi.read(); if(c != '-') { throw new SSH2FatalException("Corrupt or unsupported key file: " + fileName); } pbi.unread(c); armour = new ASCIIArmour("----"); byte[] keyBlob = armour.decode(pbi); pbi.close(); if(armour.getHeaderLine().indexOf("SSH2") != -1) { this.sshComFormat = true; this.keyPair = readKeyPairSSHCom(keyBlob, password); } else { this.keyPair = readKeyPair(armour, keyBlob, password); } this.subject = armour.getHeaderField(FILE_SUBJECT); this.comment = stripQuotes(armour.getHeaderField(FILE_COMMENT)); } public static byte[] expandPasswordToKey(String password, int keyLen, byte[] salt) { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); int digLen = md5.getDigestLength(); byte[] mdBuf = new byte[digLen]; byte[] key = new byte[keyLen]; int cnt = 0; while(cnt < keyLen) { if(cnt > 0) { md5.update(mdBuf); } md5.update(password.getBytes()); md5.update(salt); md5.digest(mdBuf, 0, digLen); int n = ((digLen > (keyLen - cnt)) ? keyLen - cnt : digLen); System.arraycopy(mdBuf, 0, key, cnt, n); cnt += n; } return key; } catch (Exception e) { throw new Error("Error in SSH2KeyPairFile.expandPasswordToKey: " + e); } } public static byte[] expandPasswordToKeySSHCom(String password, int keyLen) { try { if(password == null) { password = ""; } MessageDigest md5 = MessageDigest.getInstance("MD5"); int digLen = md5.getDigestLength(); byte[] buf = new byte[((keyLen + digLen) / digLen) * digLen]; int cnt = 0; while(cnt < keyLen) { md5.update(password.getBytes()); if(cnt > 0) { md5.update(buf, 0, cnt); } md5.digest(buf, cnt, digLen); cnt += digLen; } byte[] key = new byte[keyLen]; System.arraycopy(buf, 0, key, 0, keyLen); return key; } catch (Exception e) { throw new Error("Error in SSH2KeyPairFile.expandPasswordToKeySSHCom: " + e); } } private static void doCipher(int mode, String password, byte[] input, int len, byte[] output, byte[] iv) throws SSH2FatalException { byte[] key = expandPasswordToKey(password, 192 / 8, iv); try { Cipher cipher = Cipher.getInstance("3DES/CBC/PKCS5Padding"); cipher.init(mode, new SecretKeySpec(key, cipher.getAlgorithm()), new IvParameterSpec(iv)); cipher.doFinal(input, 0, len, output, 0); } catch (NoSuchAlgorithmException e) { throw new SSH2FatalException("Invalid algorithm in " + "SSH2KeyPairFile.doCipher: " + e); } catch (InvalidKeyException e) { throw new SSH2FatalException("Invalid key derived in " + "SSH2KeyPairFile.doCipher: " + e); } } private String stripQuotes(String str) throws SSH2FatalException { if(str != null && str.length() > 0 && str.charAt(0) == '"') { if(str.charAt(str.length() - 1) != '"') { throw new SSH2FatalException("Unbalanced quotes in key file comment"); } str = str.substring(1, str.length() - 1); } return str; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -