在《在Linux下如何使用openssl生成RSA公钥和私钥对》一文中,讲述了在Linux环境下如何生成RSA公钥和私钥,但在Java中,我们又是如何去很好的用它们呢?下面我来看下两个案例,特别是RSA私钥的生成是有输入密码的(在生产环境上一般都应该是这样用的),即在产生密钥对时有输入密码,如输出了12345678。
import java.io.File; import java.io.FileReader; import java.io.IOException; import java.security.KeyPair; import java.security.PrivateKey; import java.security.Security; import java.security.Signature; import java.security.interfaces.RSAPrivateKey; import java.util.Arrays; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMReader; import org.bouncycastle.openssl.PasswordFinder; import org.bouncycastle.util.encoders.Hex; public class SignatureExample { public static void main(String [] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); String message = "hello world"; File privateKey = new File("C:/test/key"); KeyPair keyPair = readKeyPair(privateKey, "12345678".toCharArray()); Signature signature = Signature.getInstance("SHA256WithRSAEncryption"); signature.initSign(keyPair.getPrivate()); signature.update(message.getBytes()); byte [] signatureBytes = signature.sign(); System.out.println(new String(Hex.encode(signatureBytes))); Signature verifier = Signature.getInstance("SHA256WithRSAEncryption"); verifier.initVerify(keyPair.getPublic()); verifier.update(message.getBytes()); if (verifier.verify(signatureBytes)) { System.out.println("Signature is valid"); } else { System.out.println("Signature is invalid"); } } private static KeyPair readKeyPair(File privateKey, char [] keyPassword) throws IOException { FileReader fileReader = new FileReader(privateKey); PEMReader r = new PEMReader(fileReader, new DefaultPasswordFinder(keyPassword)); try { return (KeyPair) r.readObject(); } catch (IOException ex) { throw new IOException("The private key could not be decrypted", ex); } finally { r.close(); fileReader.close(); } } private static class DefaultPasswordFinder implements PasswordFinder { private final char [] password; private DefaultPasswordFinder(char [] password) { this.password = password; } @Override public char[] getPassword() { return Arrays.copyOf(password, password.length); } } }
二.通过JSch上传文件到SFTP,并从SFTP服务器上下载
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.security.GeneralSecurityException; import java.util.Date; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.io.Closeables; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import com.jcraft.jsch.SftpATTRS; import com.jcraft.jsch.SftpException; public class SftpUtil { private final static Logger logger = LoggerFactory.getLogger(SftpUtil.class); private final static String STYLE_yyyyMMdd = "yyyyMMdd"; public static String getCurrentDir() { return new SimpleDateFormat(STYLE_yyyyMMdd).format(new Date()); } private static boolean isDirExist(ChannelSftp sftp, String directory) { boolean isDirExistFlag = false; try { SftpATTRS sftpATTRS = sftp.lstat(directory); isDirExistFlag = sftpATTRS.isDir(); }catch(Exception e) { isDirExistFlag = false; } return isDirExistFlag; } private static boolean createDir(ChannelSftp sftp, String dirPath) { boolean res = false; try { sftp.cd("/"); if(isDirExist(sftp, dirPath)) { return true; } String pathArray[] = dirPath.split("/"); for(String path : pathArray) { if(path.equals("")) { continue; } if(isDirExist(sftp, path)) { sftp.cd(path); }else { sftp.mkdir(path); sftp.cd(path); } } res = true; }catch(Exception e) { res = false; logger.warn("创建目录异常!", e); }finally { try { sftp.cd("/"); } catch (SftpException e) { logger.warn("切换到根目录异常!", e); } } return res; } /** * 上传文件 */ public static void upload(String user, String ip, int port, String password, String privateKeyPath, String passPhrase, String remoteFileName, String remoteFilePath, String localFileName) throws Exception { ChannelSftp sftp = null; FileInputStream input = null; Session sshSession = null; try { JSch jsch = new JSch(); sshSession = jsch.getSession(user, ip, port); // 判断鉴权方式 if(StringUtils.isNotEmpty(password)) { sshSession.setPassword(password); }else if(StringUtils.isNotEmpty(passPhrase)){ jsch.addIdentity(privateKeyPath, passPhrase); }else { jsch.addIdentity(privateKeyPath); } sshSession.setConfig("StrictHostKeyChecking", "no"); sshSession.connect(); Channel channel = sshSession.openChannel("sftp"); channel.connect(); sftp = (ChannelSftp) channel; if (sftp != null && sftp.isConnected()) { File file = new File(localFileName); input = new FileInputStream(file); if(remoteFilePath != null && StringUtils.isNotEmpty(remoteFilePath.trim())) { if(createDir(sftp, remoteFilePath.trim())) { sftp.cd(remoteFilePath.trim()); } } sftp.put(input, remoteFileName); sftp.quit(); } } finally { if (input != null) { try { Closeables.close(input, false); } finally { input = null; } } if (sftp != null) { try { sftp.disconnect(); } finally { sftp = null; } } if (sshSession != null) { try { sshSession.disconnect(); } finally { sshSession = null; } } } } /** * 下载文件 */ public static void download(String user, String ip, int port, String password, String privateKeyPath, String passPhrase, String remoteFileName, String remoteFilePath, String localFileName) throws Exception { ChannelSftp sftp = null; OutputStream output = null; Session sshSession = null; try { JSch jsch = new JSch(); sshSession = jsch.getSession(user, ip, port); // 判断鉴权方式 if(StringUtils.isNotEmpty(password)) { sshSession.setPassword(password); }else if(StringUtils.isNotEmpty(passPhrase)){ jsch.addIdentity(privateKeyPath, passPhrase); }else { jsch.addIdentity(privateKeyPath); } sshSession.setConfig("StrictHostKeyChecking", "no"); sshSession.connect(); Channel channel = sshSession.openChannel("sftp"); channel.connect(); sftp = (ChannelSftp) channel; if (sftp != null && sftp.isConnected()) { if(remoteFilePath != null && StringUtils.isNotEmpty(remoteFilePath.trim())) { if(createDir(sftp, remoteFilePath.trim())) { sftp.cd(remoteFilePath.trim()); } } output = new FileOutputStream(localFileName, true); sftp.get(remoteFileName, output); sftp.quit(); } } finally { if (output != null) { try { Closeables.close(output, false); } finally { output = null; } } if (sftp != null) { try { sftp.disconnect(); } finally { sftp = null; } } if (sshSession != null) { try { sshSession.disconnect(); } finally { sshSession = null; } } } } public static void main(String[] args) throws Exception { //upload("sftpuser", "10.107.97.20", 57001, null, "C:/Users/bijian/Desktop/test/key", "123456", "a.txt", getCurrentDir(), "C:/Users/bijian/Desktop/bijian.txt"); download("sftpuser", "10.107.97.20", 57001, null, "C:/Users/bijian/Desktop/test/key", "123456", "b.txt", getCurrentDir(), "C:/Users/bijian/Desktop/bijian02.txt"); //upload("sftpuser", "10.107.97.20", 57001, "12345678", null, null, "a.txt", getCurrentDir(), "C:/Users/bijian/Desktop/bijian.txt"); download("sftpuser", "10.107.97.20", 57001, "12345678", null, null, "b.txt", getCurrentDir(), "C:/Users/bijian/Desktop/bijian02.txt"); } }
参考文章:https://stackoverflow.com/questions/1580012/using-a-pem-encoded-encrypted-private-key-to-sign-a-message-natively