/* * Copyright 2015 Kevin Herron * * 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 com.digitalpetri.opcua.stack.core.util; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import com.digitalpetri.opcua.stack.core.StatusCodes; import com.digitalpetri.opcua.stack.core.UaRuntimeException; /** * <pre> * <b>P_SHA-1(secret, seed)</b> = * HMAC_SHA-1(secret, A(1) + seed) + * HMAC_SHA-1(secret, A(2) + seed) + * HMAC_SHA-1(secret, A(3) + seed) + ... * <i>Where + indicates concatenation.</i> * <br> * A() is defined as: * A(0) = seed * A(i) = HMAC_SHA-1(secret, A(i-1)) * </pre> */ public class PShaUtil { public static byte[] createPSha1Key(byte[] secret, byte[] seed, int offset, int length) { return createKey("HmacSHA1", secret, seed, offset, length); } public static byte[] createPSha256Key(byte[] secret, byte[] seed, int offset, int length) { return createKey("HmacSHA256", secret, seed, offset, length); } private static byte[] createKey(String transformation, byte[] secret, byte[] seed, int offset, int length) { try { Mac mac = Mac.getInstance(transformation); byte[] tempBytes = P_hash(transformation, secret, seed, mac, offset + length); byte[] key = new byte[length]; System.arraycopy(tempBytes, offset, key, 0, key.length); return key; } catch (Exception e) { throw new UaRuntimeException(StatusCodes.Bad_InternalError, e); } } private static byte[] P_hash(String transformation, byte[] secret, byte[] seed, Mac mac, int required) throws Exception { byte[] out = new byte[required]; int offset = 0; int toCopy; byte[] A = seed; byte[] tmp; while (required > 0) { SecretKeySpec key = new SecretKeySpec(secret, transformation); mac.init(key); mac.update(A); A = mac.doFinal(); mac.reset(); mac.init(key); mac.update(A); mac.update(seed); tmp = mac.doFinal(); toCopy = min(required, tmp.length); System.arraycopy(tmp, 0, out, offset, toCopy); offset += toCopy; required -= toCopy; } return out; } private static int min(int a, int b) { return (a > b) ? b : a; } }