Пример #1
0
  /**
   * Decrypts the User-Password attribute.
   *
   * @see org.tinyradius.packet.RadiusPacket#decodeRequestAttributes(java.lang.String)
   */
  protected void decodeRequestAttributes(String sharedSecret) throws RadiusException {
    // detect auth protocol
    RadiusAttribute userPassword = getAttribute(USER_PASSWORD);
    RadiusAttribute chapPassword = getAttribute(CHAP_PASSWORD);
    RadiusAttribute chapChallenge = getAttribute(CHAP_CHALLENGE);

    if (userPassword != null) {
      setAuthProtocol(AUTH_PAP);
      this.password =
          decodePapPassword(userPassword.getAttributeData(), RadiusUtil.getUtf8Bytes(sharedSecret));
      // copy truncated data
      userPassword.setAttributeData(RadiusUtil.getUtf8Bytes(this.password));
    } else if (chapPassword != null && chapChallenge != null) {
      setAuthProtocol(AUTH_CHAP);
      this.chapPassword = chapPassword.getAttributeData();
      this.chapChallenge = chapChallenge.getAttributeData();
    } else if (chapPassword != null && getAuthenticator().length == 16) {
      // thanks to Guillaume Tartayre
      setAuthProtocol(AUTH_CHAP);
      this.chapPassword = chapPassword.getAttributeData();
      this.chapChallenge = getAuthenticator();
    } else
      throw new RadiusException(
          "Access-Request: User-Password or CHAP-Password/CHAP-Challenge missing");
  }
Пример #2
0
  /**
   * Decodes the passed encrypted password and returns the clear-text form.
   *
   * @param encryptedPass encrypted password
   * @param sharedSecret shared secret
   * @return decrypted password
   */
  private String decodePapPassword(byte[] encryptedPass, byte[] sharedSecret)
      throws RadiusException {
    if (encryptedPass == null || encryptedPass.length < 16) {
      // PAP passwords require at least 16 bytes
      logger.warn(
          "invalid Radius packet: User-Password attribute with malformed PAP password, length = "
              + (encryptedPass == null ? 0 : encryptedPass.length)
              + ", but length must be greater than 15");
      throw new RadiusException("malformed User-Password attribute");
    }

    MessageDigest md5 = getMd5Digest();
    byte[] lastBlock = new byte[16];

    for (int i = 0; i < encryptedPass.length; i += 16) {
      md5.reset();
      md5.update(sharedSecret);
      md5.update(i == 0 ? getAuthenticator() : lastBlock);
      byte bn[] = md5.digest();

      System.arraycopy(encryptedPass, i, lastBlock, 0, 16);

      // perform the XOR as specified by RFC 2865.
      for (int j = 0; j < 16; j++) encryptedPass[i + j] = (byte) (bn[j] ^ encryptedPass[i + j]);
    }

    // remove trailing zeros
    int len = encryptedPass.length;
    while (len > 0 && encryptedPass[len - 1] == 0) len--;
    byte[] passtrunc = new byte[len];
    System.arraycopy(encryptedPass, 0, passtrunc, 0, len);

    // convert to string
    return RadiusUtil.getStringFromUtf8(passtrunc);
  }
Пример #3
0
  /**
   * Sets and encrypts the User-Password attribute.
   *
   * @see org.tinyradius.packet.RadiusPacket#encodeRequestAttributes(java.lang.String)
   */
  protected void encodeRequestAttributes(String sharedSecret) {
    if (password == null || password.length() == 0) return;
    // ok for proxied packets whose CHAP password is already encrypted
    // throw new RuntimeException("no password set");

    if (getAuthProtocol().equals(AUTH_PAP)) {
      byte[] pass =
          encodePapPassword(
              RadiusUtil.getUtf8Bytes(this.password), RadiusUtil.getUtf8Bytes(sharedSecret));
      removeAttributes(USER_PASSWORD);
      addAttribute(new RadiusAttribute(USER_PASSWORD, pass));
    } else if (getAuthProtocol().equals(AUTH_CHAP)) {
      byte[] challenge = createChapChallenge();
      byte[] pass = encodeChapPassword(password, challenge);
      removeAttributes(CHAP_PASSWORD);
      removeAttributes(CHAP_CHALLENGE);
      addAttribute(new RadiusAttribute(CHAP_PASSWORD, pass));
      addAttribute(new RadiusAttribute(CHAP_CHALLENGE, challenge));
    }
  }
Пример #4
0
  /**
   * Encodes a plain-text password using the given CHAP challenge.
   *
   * @param plaintext plain-text password
   * @param chapChallenge CHAP challenge
   * @return CHAP-encoded password
   */
  private byte[] encodeChapPassword(String plaintext, byte[] chapChallenge) {
    // see RFC 2865 section 2.2
    byte chapIdentifier = (byte) random.nextInt(256);
    byte[] chapPassword = new byte[17];
    chapPassword[0] = chapIdentifier;

    MessageDigest md5 = getMd5Digest();
    md5.reset();
    md5.update(chapIdentifier);
    md5.update(RadiusUtil.getUtf8Bytes(plaintext));
    byte[] chapHash = md5.digest(chapChallenge);

    System.arraycopy(chapHash, 0, chapPassword, 1, 16);
    return chapPassword;
  }
Пример #5
0
  /**
   * Verifies a CHAP password against the given plaintext password.
   *
   * @return plain-text password
   */
  private boolean verifyChapPassword(String plaintext) throws RadiusException {
    if (plaintext == null || plaintext.length() == 0)
      throw new IllegalArgumentException("plaintext must not be empty");
    if (chapChallenge == null || chapChallenge.length != 16)
      throw new RadiusException("CHAP challenge must be 16 bytes");
    if (chapPassword == null || chapPassword.length != 17)
      throw new RadiusException("CHAP password must be 17 bytes");

    byte chapIdentifier = chapPassword[0];
    MessageDigest md5 = getMd5Digest();
    md5.reset();
    md5.update(chapIdentifier);
    md5.update(RadiusUtil.getUtf8Bytes(plaintext));
    byte[] chapHash = md5.digest(chapChallenge);

    // compare
    for (int i = 0; i < 16; i++) if (chapHash[i] != chapPassword[i + 1]) return false;
    return true;
  }