![JAR search and dependency download from the Maven repository](/logo.png)
com.intel.bluetooth.obex.OBEXAuthentication Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bluecove Show documentation
Show all versions of bluecove Show documentation
BlueCove is JSR-82 J2SE implementation that currently interfaces with the Mac OS X, WIDCOMM, BlueSoleil and Microsoft Bluetooth stack
The newest version!
/**
* BlueCove - Java library for Bluetooth
* Copyright (C) 2007-2008 Vlad Skarzhevskyy
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @author vlads
* @version $Id: OBEXAuthentication.java 2641 2008-12-22 23:28:52Z skarzhevskyy $
*/
package com.intel.bluetooth.obex;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Vector;
import javax.obex.Authenticator;
import javax.obex.PasswordAuthentication;
import javax.obex.ServerRequestHandler;
import com.intel.bluetooth.DebugLog;
class OBEXAuthentication {
private static byte[] privateKey;
private static long uniqueTimestamp = 0;
private static final byte COLUMN[] = { ':' };
static class Challenge {
private String realm;
private boolean isUserIdRequired;
private boolean isFullAccess;
byte nonce[];
Challenge(byte data[]) throws IOException {
this.read(data);
}
Challenge(String realm, boolean isUserIdRequired, boolean isFullAccess, byte[] nonce) {
this.realm = realm;
this.isUserIdRequired = isUserIdRequired;
this.isFullAccess = isFullAccess;
this.nonce = nonce;
}
byte[] write() {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
buf.write(0x00); // Tag
buf.write(0x10); // Len
buf.write(nonce, 0, 0x10);
byte options = (byte) ((isUserIdRequired ? 1 : 0) | ((!isFullAccess) ? 2 : 0));
buf.write(0x01); // Tag
buf.write(0x01); // Len
buf.write(options);
if (realm != null) {
byte realmArray[];
byte charSetCode;
try {
realmArray = OBEXUtils.getUTF16Bytes(realm);
charSetCode = -1; // 0xFF; Unicode
} catch (UnsupportedEncodingException e) {
try {
realmArray = realm.getBytes("iso-8859-1");
} catch (UnsupportedEncodingException e1) {
realmArray = new byte[0];
}
charSetCode = 1; // iso-8859-1
}
buf.write(0x02); // Tag
buf.write(realmArray.length + 1); // Len
buf.write(charSetCode);
buf.write(realmArray, 0, realmArray.length);
}
return buf.toByteArray();
}
void read(byte data[]) throws IOException {
DebugLog.debug("authChallenge", data);
for (int i = 0; i < data.length;) {
int tag = data[i] & 0xFF;
int len = data[i + 1] & 0xFF;
i += 2;
switch (tag) {
case 0:
if (len != 0x10) {
throw new IOException("OBEX Digest Challenge error in tag Nonce");
}
nonce = new byte[0x10];
System.arraycopy(data, i, nonce, 0, 0x10);
break;
case 1:
byte options = data[i];
DebugLog.debug("authChallenge options", options);
isUserIdRequired = ((options & 1) != 0);
isFullAccess = ((options & 2) == 0);
break;
case 2:
int charSetCode = data[i] & 0xFF;
byte chars[] = new byte[len - 1];
System.arraycopy(data, i + 1, chars, 0, chars.length);
if (charSetCode == 0xFF) {
realm = OBEXUtils.newStringUTF16(chars);
} else if (charSetCode == 0) {
realm = new String(chars, "ASCII");
} else if (charSetCode <= 9) {
realm = new String(chars, "ISO-8859-" + charSetCode);
} else {
DebugLog.error("Unsupported charset code " + charSetCode + " in Challenge");
// throw new UnsupportedEncodingException("charset code
// " + charSetCode);
// BUG on SE K790a
realm = new String(chars, 0, len - 1, "ASCII");
}
break;
default:
DebugLog.error("invalid authChallenge tag " + tag);
}
i += len;
}
}
public boolean isUserIdRequired() {
return isUserIdRequired;
}
public boolean isFullAccess() {
return isFullAccess;
}
public String getRealm() {
return realm;
}
}
static class DigestResponse {
byte requestDigest[];
byte userName[];
byte nonce[];
byte[] write() {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
buf.write(0x00); // Tag
buf.write(0x10); // Len
buf.write(requestDigest, 0, 0x10);
if (userName != null) {
buf.write(0x01); // Tag
buf.write(userName.length); // Len
buf.write(userName, 0, userName.length);
}
buf.write(0x02); // Tag
buf.write(0x10); // Len
buf.write(nonce, 0, 0x10);
return buf.toByteArray();
}
void read(byte data[]) throws IOException {
for (int i = 0; i < data.length;) {
int tag = data[i] & 0xFF;
int len = data[i + 1] & 0xFF;
i += 2;
switch (tag) {
case 0:
if (len != 0x10) {
throw new IOException("OBEX Digest Response error in tag request-digest");
}
requestDigest = new byte[0x10];
System.arraycopy(data, i, requestDigest, 0, 0x10);
break;
case 1:
userName = new byte[len];
System.arraycopy(data, i, userName, 0, userName.length);
break;
case 2:
if (len != 0x10) {
throw new IOException("OBEX Digest Response error in tag Nonce");
}
nonce = new byte[0x10];
System.arraycopy(data, i, nonce, 0, 0x10);
break;
}
i += len;
}
}
}
static byte[] createChallenge(String realm, boolean isUserIdRequired, boolean isFullAccess) {
Challenge challenge = new Challenge(realm, isUserIdRequired, isFullAccess, createNonce());
return challenge.write();
}
static boolean handleAuthenticationResponse(OBEXHeaderSetImpl incomingHeaders, Authenticator authenticator,
ServerRequestHandler serverHandler, Vector authChallengesSent) throws IOException {
if (!incomingHeaders.hasAuthenticationResponses()) {
return false;
}
for (Enumeration iter = incomingHeaders.getAuthenticationResponses(); iter.hasMoreElements();) {
byte[] authResponse = (byte[]) iter.nextElement();
DigestResponse dr = new DigestResponse();
dr.read(authResponse);
DebugLog.debug("got nonce", dr.nonce);
// Verify that we did sent the Challenge that triggered this Responses
Challenge challengeSent = null;
for (Enumeration challengeIter = authChallengesSent.elements(); challengeIter.hasMoreElements();) {
Challenge c = (Challenge) challengeIter.nextElement();
if (equals(c.nonce, dr.nonce)) {
challengeSent = c;
break;
}
}
if (challengeSent == null) {
throw new IOException("Authentication response for unknown challenge");
}
byte[] password = authenticator.onAuthenticationResponse(dr.userName);
if (password == null) {
throw new IOException("Authentication request failed, password is not supplied");
}
// DebugLog.debug("authenticate using password", new String(password));
// DebugLog.debug("password used", password);
MD5DigestWrapper md5 = new MD5DigestWrapper();
md5.update(dr.nonce);
md5.update(COLUMN);
md5.update(password);
byte[] claulated = md5.digest();
if (!equals(dr.requestDigest, claulated)) {
DebugLog.debug("got digest", dr.requestDigest);
DebugLog.debug(" expected", claulated);
if (serverHandler != null) {
serverHandler.onAuthenticationFailure(dr.userName);
} else {
throw new IOException("Authentication failure");
}
} else {
return true;
}
}
return false;
}
static void handleAuthenticationChallenge(OBEXHeaderSetImpl incomingHeaders, OBEXHeaderSetImpl replyHeaders,
Authenticator authenticator) throws IOException {
if (!incomingHeaders.hasAuthenticationChallenge()) {
return;
}
for (Enumeration iter = incomingHeaders.getAuthenticationChallenges(); iter.hasMoreElements();) {
byte[] authChallenge = (byte[]) iter.nextElement();
Challenge challenge = new Challenge(authChallenge);
PasswordAuthentication pwd = authenticator.onAuthenticationChallenge(challenge.getRealm(), challenge
.isUserIdRequired(), challenge.isFullAccess());
DigestResponse dr = new DigestResponse();
dr.nonce = challenge.nonce;
DebugLog.debug("got nonce", dr.nonce);
if (challenge.isUserIdRequired()) {
dr.userName = pwd.getUserName();
}
MD5DigestWrapper md5 = new MD5DigestWrapper();
md5.update(dr.nonce);
md5.update(COLUMN);
md5.update(pwd.getPassword());
dr.requestDigest = md5.digest();
// DebugLog.debug("password", new String(pwd.getPassword()));
// DebugLog.debug("password used", pwd.getPassword());
DebugLog.debug("send digest", dr.requestDigest);
replyHeaders.addAuthenticationResponse(dr.write());
}
}
private static synchronized byte[] createNonce() {
MD5DigestWrapper md5 = new MD5DigestWrapper();
md5.update(createTimestamp());
md5.update(COLUMN);
md5.update(getPrivateKey());
return md5.digest();
}
static boolean equals(byte[] digest1, byte[] digest2) {
for (int i = 0; i < 0x10; i++) {
if (digest1[i] != digest2[i]) {
return false;
}
}
return true;
}
private static synchronized byte[] getPrivateKey() {
if (privateKey != null) {
return privateKey;
}
MD5DigestWrapper md5 = new MD5DigestWrapper();
md5.update(createTimestamp());
privateKey = md5.digest();
return privateKey;
}
private static synchronized byte[] createTimestamp() {
long t = System.currentTimeMillis();
if (t <= uniqueTimestamp) {
t = uniqueTimestamp + 1;
}
uniqueTimestamp = t;
byte[] buf = new byte[8];
for (int i = 0; i < buf.length; i++) {
buf[i] = (byte) (t >> (buf.length - 1 << 3));
t <<= 8;
}
return buf;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy