📄 ssh2keypairfile.java
字号:
/****************************************************************************** * * Copyright (c) 1999-2003 AppGate Network Security AB. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code as * defined in and that are subject to the MindTerm Public Source License, * Version 2.0, (the 'License'). You may not use this file except in compliance * with the License. * * You should have received a copy of the MindTerm Public Source License * along with this software; see the file LICENSE. If not, write to * AppGate Network Security AB, Otterhallegatan 2, SE-41118 Goteborg, SWEDEN * *****************************************************************************/package com.mindbright.ssh2;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.PushbackInputStream;import java.io.IOException;import java.math.BigInteger;import com.mindbright.jca.security.KeyPair;import com.mindbright.jca.security.PublicKey;import com.mindbright.jca.security.KeyFactory;import com.mindbright.jca.security.MessageDigest;import com.mindbright.jca.security.SecureRandom;import com.mindbright.jca.security.InvalidKeyException;import com.mindbright.jca.security.NoSuchAlgorithmException;import com.mindbright.jca.security.interfaces.DSAParams;import com.mindbright.jca.security.interfaces.DSAPublicKey;import com.mindbright.jca.security.interfaces.RSAPublicKey;import com.mindbright.jca.security.interfaces.DSAPrivateKey;import com.mindbright.jca.security.interfaces.RSAPrivateCrtKey;import com.mindbright.jca.security.spec.KeySpec;import com.mindbright.jca.security.spec.DSAPublicKeySpec;import com.mindbright.jca.security.spec.DSAPrivateKeySpec;import com.mindbright.jca.security.spec.RSAPublicKeySpec;import com.mindbright.jca.security.spec.RSAPrivateCrtKeySpec;import com.mindbright.jce.crypto.Cipher;import com.mindbright.jce.crypto.spec.SecretKeySpec;import com.mindbright.jce.crypto.spec.IvParameterSpec;import com.mindbright.security.pkcs1.RSAPrivateKey;import com.mindbright.asn1.ASN1Object;import com.mindbright.asn1.ASN1OIDRegistry;import com.mindbright.asn1.ASN1Sequence;import com.mindbright.asn1.ASN1Integer;import com.mindbright.asn1.ASN1DER;import com.mindbright.util.ASCIIArmour;import com.mindbright.util.HexDump;/** * This class implements the file formats commonly used for storing key pairs * for public key authentication. It can handle both OpenSSH's PEM file format * aswell as SSH Communications proprietary format for DSA keys. When * importing/exporting use the appropriate constructor and the load/store * methods. Note that this class can also be used to convert key pair files * between the formats. * * @see SSH2PublicKeyFile */public class SSH2KeyPairFile { private final static int TYPE_PEM_DSA = 0; private final static int TYPE_PEM_RSA = 1; private final static int TYPE_SSHCOM_DSA = 2; public final static String[] BEGIN_PRV_KEY = { "-----BEGIN DSA PRIVATE KEY-----", "-----BEGIN RSA PRIVATE KEY-----", "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" }; public final static String[] END_PRV_KEY = { "-----END DSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", "---- END SSH2 ENCRYPTED PRIVATE KEY ----" }; public final static int SSH_PRIVATE_KEY_MAGIC = 0x3f6ff9eb; public final static String PRV_PROCTYPE = "Proc-Type"; public final static String PRV_DEKINFO = "DEK-Info"; public final static String FILE_SUBJECT = "Subject"; public final static String FILE_COMMENT = "Comment"; private KeyPair keyPair; private ASCIIArmour armour; private String subject; private String comment; private boolean sshComFormat; static { ASN1OIDRegistry.addModule("com.mindbright.security.pkcs1"); } /** * Handles PEM encoding of a DSA key. From OpenSSL doc for dsa. * <p> * <pre> * PEMDSAPrivate ::= SEQUENCE { * version Version, * p INTEGER, * q INTEGER, * g INTEGER, * y INTEGER, * x INTEGER * } * * Version ::= INTEGER { openssl(0) } * </pre> * (OpenSSL currently hardcodes version to 0) */ public static final class PEMDSAPrivate extends ASN1Sequence { public ASN1Integer version; public ASN1Integer p; public ASN1Integer q; public ASN1Integer g; public ASN1Integer y; public ASN1Integer x; public PEMDSAPrivate() { version = new ASN1Integer(); p = new ASN1Integer(); q = new ASN1Integer(); g = new ASN1Integer(); y = new ASN1Integer(); x = new ASN1Integer(); addComponent(version); addComponent(p); addComponent(q); addComponent(g); addComponent(y); addComponent(x); } public PEMDSAPrivate(int version, BigInteger p, BigInteger q, BigInteger g, BigInteger y, BigInteger x) { this(); this.version.setValue(version); this.p.setValue(p); this.q.setValue(q); this.g.setValue(g); this.y.setValue(y); this.x.setValue(x); } } /** * This is the constructor used for storing a key pair. * * @param keyPair the key pair to store * @param subject the subject name of the key owner * @param comment a comment to accompany the key */ public SSH2KeyPairFile(KeyPair keyPair, String subject, String comment) { this.keyPair = keyPair; this.armour = new ASCIIArmour("----"); this.subject = subject; this.comment = comment; } /** * This is the constructor used for loading a key pair. */ public SSH2KeyPairFile() { this(null, null, null); } public KeyPair getKeyPair() { return keyPair; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public ASCIIArmour getArmour() { return armour; } public boolean isSSHComFormat() { return sshComFormat; } public String getAlgorithmName() { PublicKey publicKey = keyPair.getPublic(); String alg = null; if(publicKey instanceof DSAPublicKey) { alg = "ssh-dss"; } else if(publicKey instanceof RSAPublicKey) { alg = "ssh-rsa"; } return alg; } public int getBitLength() { PublicKey publicKey = keyPair.getPublic(); if(publicKey instanceof DSAPublicKey) { return ((DSAPublicKey)publicKey).getParams().getP().bitLength(); } else { return ((RSAPublicKey)publicKey).getModulus().bitLength(); } } public static byte[] writeKeyPair(ASCIIArmour armour, String password, SecureRandom random, KeyPair keyPair) throws SSH2FatalException { ASN1Object pem; PublicKey publicKey = keyPair.getPublic(); int headType; if(publicKey instanceof DSAPublicKey) { DSAPublicKey pubKey = (DSAPublicKey)keyPair.getPublic(); DSAPrivateKey prvKey = (DSAPrivateKey)keyPair.getPrivate(); DSAParams params = pubKey.getParams(); PEMDSAPrivate dsa = new PEMDSAPrivate(0, params.getP(), params.getQ(), params.getG(), pubKey.getY(), prvKey.getX()); pem = dsa; headType = TYPE_PEM_DSA; } else if(publicKey instanceof RSAPublicKey) { RSAPublicKey pubKey = (RSAPublicKey)keyPair.getPublic(); RSAPrivateCrtKey prvKey = (RSAPrivateCrtKey)keyPair.getPrivate(); RSAPrivateKey rsa = new RSAPrivateKey(0, pubKey.getModulus(), pubKey.getPublicExponent(), prvKey.getPrivateExponent(), prvKey.getPrimeP(), prvKey.getPrimeQ(), prvKey.getCrtCoefficient()); pem = rsa; headType = TYPE_PEM_RSA; } else { throw new SSH2FatalException("Unsupported key type: " + publicKey); } armour.setHeaderLine(BEGIN_PRV_KEY[headType]); armour.setTailLine(END_PRV_KEY[headType]); ByteArrayOutputStream enc = new ByteArrayOutputStream(128); ASN1DER der = new ASN1DER(); try { der.encode(enc, pem); } catch (IOException e) { throw new SSH2FatalException("Error while DER encoding"); } byte[] keyBlob = enc.toByteArray(); if(password != null && password.length() > 0) { byte[] iv = new byte[8]; byte[] key; random.setSeed(keyBlob); for(int i = 0; i < 8; i++) { byte[] r = new byte[1]; do { random.nextBytes(r); iv[i] = r[0]; } while(iv[i] == 0x00); } key = expandPasswordToKey(password, 192 / 8, iv); armour.setHeaderField(PRV_PROCTYPE, "4,ENCRYPTED"); armour.setHeaderField(PRV_DEKINFO, "DES-EDE3-CBC," + HexDump.toString(iv).toUpperCase()); int encLen = (8 - (keyBlob.length % 8)) + keyBlob.length; byte[] encBuf = new byte[encLen]; doCipher(Cipher.ENCRYPT_MODE, password, keyBlob, keyBlob.length, encBuf, iv); keyBlob = encBuf; } return keyBlob; } public static byte[] writeKeyPairSSHCom(String password, String cipher, KeyPair keyPair) throws SSH2FatalException { SSH2DataBuffer toBeEncrypted = new SSH2DataBuffer(8192); int totLen = 0; DSAPublicKey pubKey = (DSAPublicKey)keyPair.getPublic(); DSAPrivateKey prvKey = (DSAPrivateKey)keyPair.getPrivate(); DSAParams params = pubKey.getParams(); if(!(pubKey instanceof DSAPublicKey)) { throw new SSH2FatalException("Unsupported key type: " + pubKey); } toBeEncrypted.writeInt(0); // unenc length (filled in below) toBeEncrypted.writeInt(0); // type 0 is explicit params (as opposed to predefined) toBeEncrypted.writeBigIntBits(params.getP()); toBeEncrypted.writeBigIntBits(params.getG()); toBeEncrypted.writeBigIntBits(params.getQ()); toBeEncrypted.writeBigIntBits(pubKey.getY()); toBeEncrypted.writeBigIntBits(prvKey.getX()); totLen = toBeEncrypted.getWPos(); toBeEncrypted.setWPos(0); toBeEncrypted.writeInt(totLen - 4); if(!cipher.equals("none")) { try { int keyLen = SSH2Preferences.getCipherKeyLen(cipher); String cipherName = SSH2Preferences.ssh2ToJCECipher(cipher); byte[] key = expandPasswordToKeySSHCom(password, keyLen); Cipher encrypt = Cipher.getInstance(cipherName); encrypt.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, encrypt.getAlgorithm())); byte[] data = toBeEncrypted.getData(); int bs = encrypt.getBlockSize(); totLen += (bs - (totLen % bs)) % bs; totLen = encrypt.doFinal(data, 0, totLen, data, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -