/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2015, Telestax Inc and individual contributors
* by the @authors tag.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.restcomm.media.ice;
import java.math.BigInteger;
import java.security.SecureRandom;
/**
* @author Henrique Rosa (henrique.rosa@telestax.com)
*
*/
public class IceAuthenticatorImpl implements IceAuthenticator {
// Control message integrity
private final SecureRandom random;
protected String ufrag;
protected String password;
protected String remoteUfrag;
protected String remotePassword;
private final StringBuilder builder;
public IceAuthenticatorImpl() {
this.random = new SecureRandom();
this.ufrag = "";
this.password = "";
this.remoteUfrag = "";
this.remotePassword = "";
this.builder = new StringBuilder();
}
public String getUfrag() {
return ufrag;
}
public String getPassword() {
return password;
}
public String getRemoteUfrag() {
return remoteUfrag;
}
public void setRemoteUfrag(String remoteUfrag) {
this.remoteUfrag = remoteUfrag;
}
public String getRemotePassword() {
return remotePassword;
}
public void setRemotePassword(String remotePassword) {
this.remotePassword = remotePassword;
}
/**
* The ice-ufrag and ice-pwd attributes MUST be chosen randomly at the beginning of a session.
*
* <p>
* The ice-ufrag attribute MUST contain at least 24 bits of randomness, and the ice-pwd attribute MUST contain at least 128
* bits of randomness.<br>
* This means that the ice-ufrag attribute will be at least 4 characters long, and the ice-pwd at least 22 characters long,
* since the grammar for these attributes allows for 6 bits of randomness per character. <br>
* The attributes MAY be longer than 4 and 22 characters, respectively, of course, up to 256 characters. The upper limit
* allows for buffer sizing in implementations. Its large upper limit allows for increased amounts of randomness to be added
* over time.
* </p>
*
* @see <a href="https://tools.ietf.org/html/rfc5245#section-15.4">RFC 5245</a>
*/
public void generateIceCredentials() {
this.ufrag = generateIceCredential(24, 4, 256);
this.password = generateIceCredential(128, 22, 256);
}
private String generateIceCredential(int numBits, int min, int max) {
// Clean string builder
this.builder.setLength(0);
// Generate random strings until minimum size is satisfied
do {
this.builder.append(new BigInteger(numBits, this.random).toString(32));
} while (this.builder.length() < min);
// Trim string if it surpasses maximum size
if (builder.length() > max) {
builder.setLength(max);
}
return this.builder.toString();
}
@Override
public byte[] getLocalKey(String ufrag) {
if (isUserRegistered(ufrag)) {
if (this.password != null) {
return this.password.getBytes();
}
}
return null;
}
@Override
public byte[] getRemoteKey(String ufrag, String media) {
// Check whether full username is provided or just the fragment
int colon = ufrag.indexOf(":");
if (colon < 0) {
if (ufrag.equals(this.remoteUfrag)) {
return this.remotePassword.getBytes();
}
} else {
if (ufrag.equals(this.ufrag)) {
if (this.remotePassword != null) {
return this.remotePassword.getBytes();
}
}
}
return null;
}
@Override
public boolean isUserRegistered(String ufrag) {
int colon = ufrag.indexOf(":");
String result = colon < 0 ? ufrag : ufrag.substring(0, colon);
return result.equals(this.ufrag);
}
@Override
public boolean validateUsername(String username) {
// Username must separate local and remote ufrags with a colon
int colon = username.indexOf(":");
if (colon == -1) {
return false;
}
// Local ufrag must match the one generated by this agent
return username.substring(0, colon).equals(this.ufrag);
}
public void reset() {
this.ufrag = "";
this.password = "";
this.remoteUfrag = "";
this.remotePassword = "";
}
}