/* * 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.channel; import java.util.Optional; import com.digitalpetri.opcua.stack.core.security.SecurityAlgorithm; import com.digitalpetri.opcua.stack.core.types.builtin.ByteString; import com.digitalpetri.opcua.stack.core.types.structured.ChannelSecurityToken; import com.digitalpetri.opcua.stack.core.util.PShaUtil; public class ChannelSecurity { private final SecuritySecrets currentKeys; private final ChannelSecurityToken currentToken; private final Optional<SecuritySecrets> previousKeys; private final Optional<ChannelSecurityToken> previousToken; public ChannelSecurity(SecuritySecrets currentSecuritySecrets, ChannelSecurityToken currentToken) { this(currentSecuritySecrets, currentToken, null, null); } public ChannelSecurity(SecuritySecrets currentKeys, ChannelSecurityToken currentToken, SecuritySecrets previousKeys, ChannelSecurityToken previousToken) { this.currentKeys = currentKeys; this.currentToken = currentToken; this.previousKeys = Optional.ofNullable(previousKeys); this.previousToken = Optional.ofNullable(previousToken); } public SecuritySecrets getCurrentKeys() { return currentKeys; } public ChannelSecurityToken getCurrentToken() { return currentToken; } public Optional<SecuritySecrets> getPreviousKeys() { return previousKeys; } public Optional<ChannelSecurityToken> getPreviousToken() { return previousToken; } public static SecuritySecrets generateKeyPair(SecureChannel channel, ByteString clientNonce, ByteString serverNonce) { SecurityAlgorithm keyDerivation = channel.getSecurityPolicy().getKeyDerivationAlgorithm(); int signatureKeySize = channel.getSymmetricSignatureKeySize(); int encryptionKeySize = channel.getSymmetricEncryptionKeySize(); int cipherTextBlockSize = channel.getSymmetricCipherTextBlockSize(); assert (clientNonce != null); assert (serverNonce != null); byte[] clientSignatureKey = (keyDerivation == SecurityAlgorithm.PSha1) ? PShaUtil.createPSha1Key(serverNonce.bytes(), clientNonce.bytes(), 0, signatureKeySize) : PShaUtil.createPSha256Key(serverNonce.bytes(), clientNonce.bytes(), 0, signatureKeySize); byte[] clientEncryptionKey = (keyDerivation == SecurityAlgorithm.PSha1) ? PShaUtil.createPSha1Key(serverNonce.bytes(), clientNonce.bytes(), signatureKeySize, encryptionKeySize) : PShaUtil.createPSha256Key(serverNonce.bytes(), clientNonce.bytes(), signatureKeySize, encryptionKeySize); byte[] clientInitializationVector = (keyDerivation == SecurityAlgorithm.PSha1) ? PShaUtil.createPSha1Key(serverNonce.bytes(), clientNonce.bytes(), signatureKeySize + encryptionKeySize, cipherTextBlockSize) : PShaUtil.createPSha256Key(serverNonce.bytes(), clientNonce.bytes(), signatureKeySize + encryptionKeySize, cipherTextBlockSize); byte[] serverSignatureKey = (keyDerivation == SecurityAlgorithm.PSha1) ? PShaUtil.createPSha1Key(clientNonce.bytes(), serverNonce.bytes(), 0, signatureKeySize) : PShaUtil.createPSha256Key(clientNonce.bytes(), serverNonce.bytes(), 0, signatureKeySize); byte[] serverEncryptionKey = (keyDerivation == SecurityAlgorithm.PSha1) ? PShaUtil.createPSha1Key(clientNonce.bytes(), serverNonce.bytes(), signatureKeySize, encryptionKeySize) : PShaUtil.createPSha256Key(clientNonce.bytes(), serverNonce.bytes(), signatureKeySize, encryptionKeySize); byte[] serverInitializationVector = (keyDerivation == SecurityAlgorithm.PSha1) ? PShaUtil.createPSha1Key(clientNonce.bytes(), serverNonce.bytes(), signatureKeySize + encryptionKeySize, cipherTextBlockSize) : PShaUtil.createPSha256Key(clientNonce.bytes(), serverNonce.bytes(), signatureKeySize + encryptionKeySize, cipherTextBlockSize); return new SecuritySecrets( new SecretKeys(clientSignatureKey, clientEncryptionKey, clientInitializationVector), new SecretKeys(serverSignatureKey, serverEncryptionKey, serverInitializationVector) ); } public static class SecuritySecrets { private final SecretKeys clientKeys; private final SecretKeys serverKeys; public SecuritySecrets(SecretKeys clientKeys, SecretKeys serverKeys) { this.clientKeys = clientKeys; this.serverKeys = serverKeys; } public SecretKeys getClientKeys() { return clientKeys; } public SecretKeys getServerKeys() { return serverKeys; } } public static class SecretKeys { private final byte[] signatureKey; private final byte[] encryptionKey; private final byte[] initializationVector; public SecretKeys(byte[] signatureKey, byte[] encryptionKey, byte[] initializationVector) { this.signatureKey = signatureKey; this.encryptionKey = encryptionKey; this.initializationVector = initializationVector; } public byte[] getSignatureKey() { return signatureKey; } public byte[] getEncryptionKey() { return encryptionKey; } public byte[] getInitializationVector() { return initializationVector; } } }