Package org.snmp4j.security

Source Code of org.snmp4j.security.PrivDES

/*_############################################################################
  _##
  _##  SNMP4J - PrivDES.java
  _##
  _##  Copyright (C) 2003-2009  Frank Fock and Jochen Katz (SNMP4J.org)
  _##
  _##  Licensed 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.
  _##
  _##########################################################################*/

package org.snmp4j.security;

import org.snmp4j.smi.OID;
import org.snmp4j.log.*;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import org.snmp4j.smi.OctetString;

/**
* Privacy protocol class for DES.
*
* This class uses DES in CBC mode to encrypt the data. The protocol
* is defined in the IETF standard "User-based Security Model (USM)
* for SNMPv3".
*
* @author Jochen Katz
* @version 1.9
*/
public class PrivDES
    implements PrivacyProtocol {

  private static final long serialVersionUID = 2526070176429255416L;

  /**
   * Unique ID of this privacy protocol.
   */
  public static final OID ID = new OID("1.3.6.1.6.3.10.1.2.2");

  private static final int DECRYPT_PARAMS_LENGTH = 8;
  protected Salt salt;

  private static final LogAdapter logger = LogFactory.getLogger(PrivDES.class);

  public PrivDES()
  {
    this.salt = Salt.getInstance();
  }

  public byte[] encrypt(byte[] unencryptedData,
                        int offset,
                        int length,
                        byte[] encryptionKey,
                        long engineBoots,
                        long engineTime,
                        DecryptParams decryptParams) {
    int mySalt = (int)salt.getNext();

    if (encryptionKey.length < 16) {
      logger.error("Wrong Key length: need at least 16 bytes, is " +
                   encryptionKey.length +
                   " bytes.");
      throw new IllegalArgumentException("encryptionKey has illegal length "
                                         + encryptionKey.length
                                         + " (should be at least 16).");
    }

    if ( (decryptParams.array == null) || (decryptParams.length < 8)) {
      decryptParams.array = new byte[8];
    }
    decryptParams.length = 8;
    decryptParams.offset = 0;

    // put salt in decryption_params (sent as priv params)
    if (logger.isDebugEnabled()) {
      logger.debug("Preparing decrypt_params.");
    }
    for (int i = 0; i < 4; ++i) {
      decryptParams.array[3 - i] = (byte) (0xFF & (engineBoots >> (8 * i)));
      decryptParams.array[7 - i] = (byte) (0xFF & (mySalt >> (8 * i)));
    }

    byte[] iv = new byte[8];

    // last eight bytes of key xored with decrypt params are used as iv
    if (logger.isDebugEnabled()) {
      logger.debug("Preparing iv for encryption.");
    }
    for (int i = 0; i < 8; ++i) {
      iv[i] = (byte) (encryptionKey[8 + i] ^ decryptParams.array[i]);
    }

    byte[] encryptedData = null;

    try {
      // now do CBC encryption of the plaintext
      Cipher alg = Cipher.getInstance("DES/CBC/NoPadding");
      SecretKeySpec key =
          new SecretKeySpec(encryptionKey, 0, 8, "DES");
      IvParameterSpec ivSpec = new IvParameterSpec(iv);
      alg.init(Cipher.ENCRYPT_MODE, key, ivSpec);

      // allocate space for encrypted text
      if (length % 8 == 0) {
        encryptedData = alg.doFinal(unencryptedData, offset, length);
      }
      else {
        if (logger.isDebugEnabled()) {
          logger.debug("Using padding.");
        }

        encryptedData = new byte[8 * ( (length / 8) + 1)];
        byte[] tmp = new byte[8];

        int encryptedLength = alg.update(unencryptedData, offset, length,
                                         encryptedData);
        encryptedLength += alg.doFinal(tmp, 0, 8 - (length % 8),
                                       encryptedData, encryptedLength);
      }
    }
    catch (Exception e) {
      logger.error(e);
      if (logger.isDebugEnabled()) {
        e.printStackTrace();
      }
    }

    if (logger.isDebugEnabled()) {
      logger.debug("Encryption finished.");
    }
    return encryptedData;
  }

  /**
   * Decrypts a message using a given decryption key, engine boots count, and
   * engine ID.
   *
   * @param cryptedData
   * @param offset
   * @param length
   * @param decryptionKey
   * @param engineBoots
   * @param engineTime
   * @return
   *    the decrypted data, or <code>null</code> if decryption failed.
   */
  public byte[] decrypt(byte[] cryptedData,
                        int offset,
                        int length,
                        byte[] decryptionKey,
                        long engineBoots,
                        long engineTime,
                        DecryptParams decryptParams) {
    if ((length % 8 != 0) ||
        (length < 8) ||
        (decryptParams.length != 8)) {
      throw new IllegalArgumentException(
          "Length (" + length +
          ") is not multiple of 8 or decrypt params has not length 8 ("
          + decryptParams.length + ").");
    }
    if (decryptionKey.length < 16) {
      logger.error("Wrong Key length: need at least 16 bytes, is " +
                   decryptionKey.length +
                   " bytes.");
      throw new IllegalArgumentException("decryptionKey has illegal length "
                                         + decryptionKey.length
                                         + " (should be at least 16).");
    }

    byte[] iv = new byte[8];

    // last eight bytes of key xored with decrypt params are used as iv
    for (int i = 0; i < 8; ++i) {
      iv[i] = (byte) (decryptionKey[8 + i] ^ decryptParams.array[i]);
    }

    byte[] decryptedData = null;
    try {
      // now do CBC decryption of the crypted data
      Cipher alg = Cipher.getInstance("DES/CBC/NoPadding");
      SecretKeySpec key =
          new SecretKeySpec(decryptionKey, 0, 8, "DES");
      IvParameterSpec ivSpec = new IvParameterSpec(iv);
      alg.init(Cipher.DECRYPT_MODE, key, ivSpec);
      decryptedData = alg.doFinal(cryptedData, offset, length);
    }
    catch (Exception e) {
      logger.error(e);
      if (logger.isDebugEnabled()) {
        e.printStackTrace();
      }
    }

    return decryptedData;
  }

  /**
   * Gets the OID uniquely identifying the privacy protocol.
   * @return
   *    an <code>OID</code> instance.
   */
  public OID getID() {
    return (OID) ID.clone();
  }

  public int getEncryptedLength(int scopedPDULength) {
    if (scopedPDULength % 8 == 0) {
      return scopedPDULength;
    }
    return 8 * ( (scopedPDULength / 8) + 1);
  }

  public int getMinKeyLength() {
    return 16;
  }

  public int getDecryptParamsLength() {
    return DECRYPT_PARAMS_LENGTH;
  }

  public int getMaxKeyLength() {
    return getMinKeyLength();
  }

  public byte[] extendShortKey(byte[] shortKey, OctetString password,
                               byte[] engineID,
                               AuthenticationProtocol authProtocol) {
    return shortKey;
  }

}
TOP

Related Classes of org.snmp4j.security.PrivDES

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.