⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jfmauth.java

📁 java邮件源程序
💻 JAVA
字号:
/* * Created on 2004.08.17 * JFreeMail - Java mail component * Copyright (C) 2004 Dalibor Krleza *  * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. *  * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. *  * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */package org.jfreemail.core;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.BufferedOutputStream;import java.io.OutputStream;import java.net.Socket;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Vector;/** * Class used for server authentication. For now covered authentications * are PLAIN,LOGIN,APOP and CRAM-MD5. If you insist I can add other * authentications like DIGEST-MD5. I couldn't test CRAM-MD5 and * DIGEST-MD5, as I couldn't setup Sendmail with SASL autentication. * I'll apperciate if anybody could test CRAM-MD5 for SMTP. */public class JfmAuth {	/**	 * Constructor for constructing authentication object. This could be done	 * with static procedure. I realized authentication this way for future use.	 * @param client_socket Socket object for client connection.	 * @param auth_type Authentication type. Look in JfmConsts static attributes.	 * @param username User's username.	 * @param password User's secret. Deleted immediately after authentication.	 * @param challenge Passed challenge. If authentication type requires challenge. 	 * @throws AuthException Signaling authentication exception.	 */	public JfmAuth(Socket client_socket,int auth_type,	String username,String password,String challenge) 	throws AuthException {		if (username==null || password==null)			throw new AuthException("AUTH_001:No defined username or password");		if (client_socket==null)			throw new AuthException("AUTH_002:No active connection");		int retry=JfmConsts.AUTH_RETRY;		while(retry>=0) {			switch(auth_type) {				case JfmConsts.POP3_PLAIN: {					if (!pop3_plain(client_socket,username,password)) {						if (retry<1) {													try {								client_socket.close();							} catch(IOException exc1) {							}							throw new AuthException("AUTH_003:Authentication failed");						}					} else return;					break;				}				case JfmConsts.POP3_APOP: {					try {						if (!pop3_apop(client_socket,challenge,username,password)) {							if (retry<1) {								try {									client_socket.close();								} catch(IOException exc1) {								}								throw new AuthException("AUTH_003:Authentication failed");							}						} else return;					} catch(NoSuchAlgorithmException exc) {						try {							client_socket.close();						} catch(IOException exc1) {						}						throw new AuthException("AUTH_004:No MD5 algorithm");					}					break;				}				case JfmConsts.POP3_CRAM_MD5: {					try {						if (!pop3_cram_md5(client_socket,username,password)) {							if (retry<1) {								try {									client_socket.close();								} catch(IOException exc1) {								}								throw new AuthException("AUTH_003:Authentication failed");							}						} else return;					} catch(NoSuchAlgorithmException exc) {						throw new AuthException("AUTH_004:No MD5 algorithm");					}					break;				}				case JfmConsts.SMTP_LOGIN: {					if (!smtp_login(client_socket,username,password)) {						if (retry<1) {							try {								client_socket.close();							} catch(IOException exc1) {							}							throw new AuthException("AUTH_003:Authentication failed");						}					} else return;					break;				}				case JfmConsts.SMTP_CRAM_MD5: {					try {						if (!smtp_cram_md5(client_socket,username,password)) {							if (retry<1) {								try {									client_socket.close();								} catch(IOException exc1) {								}								throw new AuthException("AUTH_003:Authentication failed");							}						} else return;					} catch(NoSuchAlgorithmException exc) {						throw new AuthException("AUTH_004:No MD5 algorithm");					}					break;				}			}			retry--;			if (retry>=0) {				auth_type--;				if (auth_type==JfmConsts.POP3_NONE					|| auth_type==JfmConsts.SMTP_NONE)					throw new AuthException("AUTH_000:Exhaused all authentication types");			}		}	}		/*	 * Authentication for POP3 protocol. Plain authentication using username	 * and password. Doesn't require any encoding or challenge calculation!	 */	private boolean pop3_plain(Socket client_socket,String username,	String password) {		try {			OutputStream os=client_socket.getOutputStream();			String out1="USER "+username+String.valueOf((char)13)+String.valueOf((char)10);			os.write(out1.getBytes());			String in1=JfmSocketCore.getLine(client_socket)[0];			if (in1.indexOf(JfmConsts.POP3_OK)<0) return false;			String out2="PASS "+password+String.valueOf((char)13)+String.valueOf((char)10);			os.write(out2.getBytes());			in1=JfmSocketCore.getLine(client_socket)[0];			if (in1.indexOf(JfmConsts.POP3_OK)<0) return false;			return true;		} catch(IOException exc) {			return false;		}	}		/*	 * APOP authentication for POP3. Need challenge from POP3 server	 * for authentication. POP3 transmits challenge at the beginning of	 * communication. Challenge looks like <3873.2878733@server>.	 * We are adding password at the end of challenge and calculating	 * message digest. Message digest is then converted into hexadecimal	 * format and added like follows:	 * APOP username message-md5-digest	 */	private boolean pop3_apop(Socket client_socket,String challenge,	String username, String password) throws NoSuchAlgorithmException {		try {			OutputStream os=client_socket.getOutputStream();			MessageDigest md=MessageDigest.getInstance("MD5");			String out="APOP "+username+" ";			String temp_challenge=challenge;												out+=apop_md5(temp_challenge,password);			out+="\r\n";			os.write(out.getBytes());			String in=JfmSocketCore.getLine(client_socket)[0];			if (in.indexOf(JfmConsts.POP3_OK)<0) return false;			return true;		} catch(IOException exc) {			return false;		}	}	/*	 * CRAM-MD5 authentication for POP3. With AUTH CRAM-MD5 we	 * are requesting challenge from POP3 server. Challenge is base64	 * coded. After base64 decoding, challenge is in same format as for	 * APOP authentication. We are performing two complicated calculation	 * of MD5. Ending message digest i combined with username and base64	 * encoded. So encoded it's being transmited to POP3 server.	 * 	 * Same procedure is for SMTP CRAM-MD5 autentication!	 */	private boolean pop3_cram_md5(Socket client_socket,String username,	String password) throws NoSuchAlgorithmException {		try {			OutputStream os=client_socket.getOutputStream();			MessageDigest md=MessageDigest.getInstance("MD5");			String out="AUTH CRAM-MD5\r\n";			os.write(out.getBytes());			String challenge=JfmSocketCore.getLine(client_socket)[0];			challenge=challenge.substring(2,challenge.length()-2);			byte[] byte_challenge=JfmCore.base64decode(new String[] {challenge});			challenge="";			for(int i=0;i<byte_challenge.length;i++) if (byte_challenge[i]!=0) challenge+=(char)byte_challenge[i];												out=username+" "+cram_md5(challenge,password);			String[] out_list=JfmCore.base64encode(out.getBytes());			out=out_list[0]+"\r\n";			os.write(out.getBytes());			String in=JfmSocketCore.getLine(client_socket)[0];			if (in.indexOf(JfmConsts.POP3_OK)<0) return false;			return true;		} catch(IOException exc) {			return false;		}	}		/*	 * Login authentication for SMTP. Username and password are transmited	 * only base64 encoded.	 */	private boolean smtp_login(Socket client_socket,String username,	String password) {		try {			OutputStream os=client_socket.getOutputStream();			String out="AUTH LOGIN\r\n";			os.write(out.getBytes());			String in=JfmSocketCore.getLine(client_socket)[0];			if (in.charAt(0)=='4' || in.charAt(0)=='5') return false;			out=JfmCore.base64encode(username.getBytes())[0]+"\r\n";			os.write(out.getBytes());			in=JfmSocketCore.getLine(client_socket)[0];			if (in.charAt(0)=='4' || in.charAt(0)=='5') return false;			out=JfmCore.base64encode(password.getBytes())[0]+"\r\n";			os.write(out.getBytes());			in=JfmSocketCore.getLine(client_socket)[0];			if (in.charAt(0)=='4' || in.charAt(0)=='5') return false;			return true;		} catch(IOException exc) {			return false;		}	}		private String apop_md5(String challenge,String secret) 	throws NoSuchAlgorithmException {		MessageDigest md=MessageDigest.getInstance("MD5");		byte[] end_buffer=md.digest((challenge+secret).getBytes());		String end_string=new String("");		for(int i=0;i<16;i++) {			int ix=(int)(end_buffer[i] & 0x00FF);			if (ix>15) end_string+=Integer.toHexString(ix);			else end_string+="0"+Integer.toHexString(ix);		} 		return end_string;	}	/*	 * CRAM-MD5 authentication for SMTP. Not very different from POP3	 * CRAM-MD5. Only difference is in server responses.	 */	private boolean smtp_cram_md5(Socket client_socket,String username,	String password) throws NoSuchAlgorithmException {		try {			OutputStream os=client_socket.getOutputStream();			String out="AUTH CRAM-MD5\r\n";			os.write(out.getBytes());			String in=JfmSocketCore.getLine(client_socket)[0];			if (in.charAt(0)=='4' || in.charAt(0)=='5') return false;			in=in.substring(4,in.length()-2);			byte[] buffer=JfmCore.base64decode(new String[]{in});			out=new String();			for(int i=0;i<buffer.length;i++) out+=(char)buffer[i];			out=username+" "+cram_md5(out,password);			out=JfmCore.base64encode(out.getBytes())[0]+"\r\n";			os.write(out.getBytes());			in=JfmSocketCore.getLine(client_socket)[0];			if (in.charAt(0)=='4' || in.charAt(0)=='5') return false;			return true;		} catch(IOException exc) {			return false;		}	}		/* 	 * Basic CRAM-MD5 algorithm. RFC based. Looks like	 * MD5(secret XOR opad,MD(secret XOR ipad,challenge)).	 */	private String cram_md5(String challenge,String secret) 	throws NoSuchAlgorithmException {		byte[] secret_buffer1=expand128(secret);		byte[] secret_buffer2=expand128(secret);				for(int i=0;i<64;i++) {			secret_buffer1[i]^=(byte)0x36; //ipad			secret_buffer2[i]^=(byte)0x5C; //opad		}		for(int i=0;i<challenge.length();i++) secret_buffer1[i+64]=(byte)challenge.charAt(i);		MessageDigest md=MessageDigest.getInstance("MD5");		byte[] in1=new byte[64+challenge.length()];		for(int i=0;i<(64+challenge.length());i++) in1[i]=secret_buffer1[i];		byte[] mid_buffer=md.digest(in1);		for(int i=0;i<16;i++) secret_buffer2[i+64]=mid_buffer[i];		byte[] in2=new byte[80];		for(int i=0;i<80;i++) in2[i]=secret_buffer2[i];		byte[] end_buffer=md.digest(in2);		String end_string=new String("");		for(int i=0;i<16;i++) {			int ix=(int)(end_buffer[i] & 0x00FF);			if (ix>15) end_string+=Integer.toHexString(ix);			else end_string+="0"+Integer.toHexString(ix);		} 		return end_string;	}		/*	 * Procedure for expanding String buffer upto 128 bytes. 	 * Expanded bytes are set to 0!	 */	private byte[] expand128(String input) {		byte[] buffer=new byte[128];		for(int i=0;i<128;i++) buffer[i]=0;		int l=input.length();		if (l>64) l=64;		for(int i=0;i<l;i++) buffer[i]=(byte)input.charAt(i);		return buffer;	}		/*	 * Procedure for expanding byte buffer upto 128 bytes.	 * Expanded bytes are set to 0!	 */	private byte[] expand128(byte[] input) {		byte[] buffer=new byte[128];		for(int i=0;i<128;i++) buffer[i]=0;		int l=input.length;		if (l>64) l=64;		for(int i=0;i<l;i++) buffer[i]=input[i];		return buffer;	}	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -