Skip to content

Commit

Permalink
Fix #665: Allow JCE KDF to work (#666)
Browse files Browse the repository at this point in the history
* Fix #665: Allow JCE KDF to work

* Add header

* Add KDF unit test
  • Loading branch information
pboyd04 authored Aug 31, 2021
1 parent 890443d commit 5c42b8f
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

public interface DerivationFunction {

void init(DerivationParameters parameters);
void init(DerivationParameters parameters) throws SecurityException;

int generateBytes(byte[] out, int outOff, int len);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
package com.hierynomus.security.jce;

import com.hierynomus.security.DerivationFunction;
import com.hierynomus.security.SecurityException;
import com.hierynomus.security.jce.derivationfunction.DerivationParameters;

public class JceDerivationFunction implements DerivationFunction {

@Override
public void init(DerivationParameters parameters) {
public void init(DerivationParameters parameters) throws SecurityException {
throw new UnsupportedOperationException();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (C)2016 - SMBJ Contributors
*
* 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.hierynomus.security.jce;

import com.hierynomus.protocol.commons.Factory;
import com.hierynomus.security.DerivationFunction;
import com.hierynomus.security.jce.derivationfunction.KDFCounterHMacSHA256;

import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

public class JceDerivationFunctionFactory {
private static final Map<String, Factory<DerivationFunction>> lookup = new HashMap<>();

static {
lookup.put("KDF/Counter/HMACSHA256", new Factory<DerivationFunction>() {
@Override
public DerivationFunction create() {
try {
return new KDFCounterHMacSHA256();
} catch(NoSuchAlgorithmException ex) {
return null;
}
}
});
}

public static DerivationFunction create(String name) {
Factory<DerivationFunction> derivationFunctionFactory = lookup.get(name);
if (derivationFunctionFactory == null) {
throw new IllegalArgumentException("Unknown DerivationFunction " + name);
}
DerivationFunction func = derivationFunctionFactory.create();
if (func == null) {
throw new IllegalArgumentException("DerivationFunction " + name + " not supported!");
}
return func;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,6 @@ public AEADBlockCipher getAEADBlockCipher(String name) throws SecurityException{

@Override
public DerivationFunction getDerivationFunction(String name) throws SecurityException {
throw new UnsupportedOperationException("Key Derivation Function is currently only supported when using the BCSecurityProvider. Please configure: `SmbConfig.withSecurityProvider(new BCSecurityProvider())` to use SMB3 support.");
return JceDerivationFunctionFactory.create(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (C)2016 - SMBJ Contributors
*
* 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.hierynomus.security.jce.derivationfunction;

import com.hierynomus.security.SecurityException;
import com.hierynomus.security.jce.JceDerivationFunction;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class KDFCounterHMacSHA256 extends JceDerivationFunction {
private Mac mac;
private byte[] fixedSuffix;
private int maxLength;

public KDFCounterHMacSHA256() throws NoSuchAlgorithmException {
mac = Mac.getInstance("HmacSHA256");
}

@Override
public void init(DerivationParameters parameters) throws SecurityException {
if (!(parameters instanceof CounterDerivationParameters)) {
throw new IllegalArgumentException("Parameters should be a CounterDerivationParameters");
}

CounterDerivationParameters p = (CounterDerivationParameters) parameters;
SecretKeySpec seed = new SecretKeySpec(p.getSeed(), "HmacSHA256");
try {
mac.init(seed);
} catch(InvalidKeyException ex) {
throw new SecurityException(ex);
}
this.fixedSuffix = p.getFixedCounterSuffix();
this.maxLength = p.getCounterLength();
}

@Override
public int generateBytes(byte[] out, int outOff, int len) {
int generated = 0;
//The number of rounds is the output length divided by the size (in bytes of the function output)
int rounds = len/32;
if ((len % 32) != 0) {
//Do one more round for the odd bytes
rounds++;
}
byte[] input = new byte[4];
for (int i = 0; i < rounds; i++) {
input[0] = (byte)((i+1) >>> 24);
input[1] = (byte)((i+1) >>> 16);
input[2] = (byte)((i+1) >>> 8);
input[3] = (byte)(i+1);
mac.update(input);
mac.update(this.fixedSuffix);
byte[] tmp = mac.doFinal();
int toCopy = tmp.length;
if ((tmp.length + generated) > len) {
toCopy = len - generated;
}
System.arraycopy(tmp, 0, out, outOff, toCopy);
generated += toCopy;
outOff += toCopy;
}
return len;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (C)2016 - SMBJ Contributors
*
* 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.hierynomus.security.jce.derivationfunction

import spock.lang.Specification
import org.codehaus.groovy.runtime.EncodingGroovyMethods

class KDFCounterHMacSHA256Spec extends Specification {

def "KDF Counter tests"() {
when:
def df = new KDFCounterHMacSHA256()
def params = new CounterDerivationParameters(EncodingGroovyMethods.decodeHex(seed), EncodingGroovyMethods.decodeHex(suffix), 32)
df.init(params)
byte[] derived = new byte[16];
df.generateBytes(derived, 0, derived.length)

then:
derived == EncodingGroovyMethods.decodeHex(expectedResults)

where:
seed << ["05748462F987037190DEF58A165E3678", "05748462F987037190DEF58A165E3678", "C3ACFDC1B070770A8DDAB9740DA29B79"]
suffix << ["534D425369676E696E674B6579000043F965A710069C1CEC7D79469C0FDE7143FB350599997C65D2B5D65B40DED490C0E13BA9F5822D2619BFEB08873909926F4BBE455321DC4C151A46B47718421F00000080" , "534D424332534369706865724B6579000043F965A710069C1CEC7D79469C0FDE7143FB350599997C65D2B5D65B40DED490C0E13BA9F5822D2619BFEB08873909926F4BBE455321DC4C151A46B47718421F00000080", "534D425369676E696E674B65790000FE8742AB31DC7A88DF45BCA328875D079E597CF711D3AFB397AF32422E9BD8541C1F0E1D665646B56A141BE700351C35FB7426F9946F22271DE0B4EDFAFBC11E00000080"]
expectedResults << ["E4F496372BB7FBA2BFCAE08AA07C9C16", "17566BCB45012959EBE074736B0EBD79", "14595AE1720357BBA5B22084041E27E9"]
}
}

0 comments on commit 5c42b8f

Please sign in to comment.