Path: blob/master/src/java.security.sasl/share/classes/com/sun/security/sasl/CramMD5Base.java
41161 views
/*1* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.security.sasl;2627import javax.security.sasl.SaslException;28import javax.security.sasl.Sasl;2930// For HMAC_MD531import java.security.NoSuchAlgorithmException;32import java.security.MessageDigest;3334import java.util.Arrays;35import java.util.logging.Logger;3637/**38* Base class for implementing CRAM-MD5 client and server mechanisms.39*40* @author Vincent Ryan41* @author Rosanna Lee42*/43abstract class CramMD5Base {44protected boolean completed = false;45protected boolean aborted = false;46protected byte[] pw;4748protected CramMD5Base() {49initLogger();50}5152/**53* Retrieves this mechanism's name.54*55* @return The string "CRAM-MD5".56*/57public String getMechanismName() {58return "CRAM-MD5";59}6061/**62* Determines whether this mechanism has completed.63* CRAM-MD5 completes after processing one challenge from the server.64*65* @return true if has completed; false otherwise;66*/67public boolean isComplete() {68return completed;69}7071/**72* Unwraps the incoming buffer. CRAM-MD5 supports no security layer.73*74* @throws SaslException If attempt to use this method.75*/76public byte[] unwrap(byte[] incoming, int offset, int len)77throws SaslException {78if (completed) {79throw new IllegalStateException(80"CRAM-MD5 supports neither integrity nor privacy");81} else {82throw new IllegalStateException(83"CRAM-MD5 authentication not completed");84}85}8687/**88* Wraps the outgoing buffer. CRAM-MD5 supports no security layer.89*90* @throws SaslException If attempt to use this method.91*/92public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException {93if (completed) {94throw new IllegalStateException(95"CRAM-MD5 supports neither integrity nor privacy");96} else {97throw new IllegalStateException(98"CRAM-MD5 authentication not completed");99}100}101102/**103* Retrieves the negotiated property.104* This method can be called only after the authentication exchange has105* completed (i.e., when {@code isComplete()} returns true); otherwise, a106* {@code SaslException} is thrown.107*108* @return value of property; only QOP is applicable to CRAM-MD5.109* @exception IllegalStateException if this authentication exchange has not completed110*/111public Object getNegotiatedProperty(String propName) {112if (completed) {113if (propName.equals(Sasl.QOP)) {114return "auth";115} else {116return null;117}118} else {119throw new IllegalStateException(120"CRAM-MD5 authentication not completed");121}122}123124public void dispose() throws SaslException {125clearPassword();126}127128protected void clearPassword() {129if (pw != null) {130// zero out password131for (int i = 0; i < pw.length; i++) {132pw[i] = (byte)0;133}134pw = null;135}136}137138@SuppressWarnings("deprecation")139protected void finalize() {140clearPassword();141}142143private static final int MD5_BLOCKSIZE = 64;144/**145* Hashes its input arguments according to HMAC-MD5 (RFC 2104)146* and returns the resulting digest in its ASCII representation.147*148* HMAC-MD5 function is described as follows:149*150* MD5(key XOR opad, MD5(key XOR ipad, text))151*152* where key is an n byte key153* ipad is the byte 0x36 repeated 64 times154* opad is the byte 0x5c repeated 64 times155* text is the data to be protected156*/157static final String HMAC_MD5(byte[] key, byte[] text)158throws NoSuchAlgorithmException {159160MessageDigest md5 = MessageDigest.getInstance("MD5");161162/* digest the key if longer than 64 bytes */163if (key.length > MD5_BLOCKSIZE) {164key = md5.digest(key);165}166167byte[] ipad = new byte[MD5_BLOCKSIZE]; /* inner padding */168byte[] opad = new byte[MD5_BLOCKSIZE]; /* outer padding */169byte[] digest;170int i;171172/* store key in pads */173for (i = 0; i < key.length; i++) {174ipad[i] = key[i];175opad[i] = key[i];176}177178/* XOR key with pads */179for (i = 0; i < MD5_BLOCKSIZE; i++) {180ipad[i] ^= 0x36;181opad[i] ^= 0x5c;182}183184/* inner MD5 */185md5.update(ipad);186md5.update(text);187digest = md5.digest();188189/* outer MD5 */190md5.update(opad);191md5.update(digest);192digest = md5.digest();193194// Get character representation of digest195StringBuilder digestString = new StringBuilder();196197for (i = 0; i < digest.length; i++) {198if ((digest[i] & 0x000000ff) < 0x10) {199digestString.append('0').append(Integer.toHexString(digest[i] & 0x000000ff));200} else {201digestString.append(202Integer.toHexString(digest[i] & 0x000000ff));203}204}205206Arrays.fill(ipad, (byte)0);207Arrays.fill(opad, (byte)0);208ipad = null;209opad = null;210211return (digestString.toString());212}213214/**215* Sets logger field.216*/217private static synchronized void initLogger() {218if (logger == null) {219logger = Logger.getLogger(SASL_LOGGER_NAME);220}221}222/**223* Logger for debug messages224*/225private static final String SASL_LOGGER_NAME = "javax.security.sasl";226protected static Logger logger; // set in initLogger(); lazily loads logger227}228229230