/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package userGeneratedContent.testbedPlugIns.layerPlugIns.layer2recodingScheme.sphinx_v0_001; import java.security.SecureRandom; import java.util.Arrays; import staticContent.framework.util.Util; public class MixHeader { public static final byte MIX_PREFIX = (byte)0; public static final byte SPECIAL_DEST_PREFIX = (byte)1; public static final byte CLIENT_PREFIX = (byte)2; private byte[] _x = new byte[32]; // the random x (private key) private byte[] _gX = new byte[32]; // g^x (public key) private byte[][] _betas; private byte[][] _gammas; private byte[][] _fillerStrings; private byte[][] _secrets; private byte[][][] _asbTuples; private Sphinx_Config config; private SecureRandom secureRandom; private Route route; public MixHeader(Sphinx_Config config, SecureRandom secureRandom, Route route) { this.config = config; this.secureRandom = secureRandom; this.route = route; byte[][] keyPair = Sphinx.generateKeyPair(config); _gX = keyPair[0]; // public _x = keyPair[1]; // private } // byte[] id == address the last mix will receive (first byte must be MIXPREFIX, SPECIAL_DEST_REQUEST or SPECIAL_DEST_REPLY) /** * Returns the Mixheader M_0: (Alpha_0, Beta_0, Gamma_0) */ public byte[][] createHeader(byte[] id) throws Exception { assert id.length == config.SECURITY_PARAMETER_SIZE; assert id[0] == MIX_PREFIX || id[0] == SPECIAL_DEST_PREFIX || id[0] == CLIENT_PREFIX; this._betas = new byte[config.ROUTE_LENGTH][]; this._gammas = new byte[config.ROUTE_LENGTH][]; this._fillerStrings = new byte[config.ROUTE_LENGTH][]; this._secrets = new byte[config.ROUTE_LENGTH][]; this._asbTuples = new byte[config.ROUTE_LENGTH][][]; computeTuples(); computeFillerStrings(); computeBetasGammas(id); return new byte[][] {_asbTuples[0][0], _betas[0], _gammas[0]}; } public byte[] getSecret(int id) { return _secrets[id]; } // generate a sequence of _r tuples: (group element, shared secret, blinding // factor) private void computeTuples() throws Exception { byte[][] blinds = new byte[config.ROUTE_LENGTH+1][]; byte[][] alphas = new byte[config.ROUTE_LENGTH][]; byte[] alpha = new byte[32]; byte[] sharedSecret = new byte[32]; byte[] blindingFactor = new byte[32]; blinds[0] = _x; // round 0 alpha = _gX; assert route.publicKeysOfMixes[0] != null; assert blinds != null; assert blinds[0] != null; sharedSecret = Sphinx.genSharedSecret(route.publicKeysOfMixes[0], blinds); blindingFactor = Sphinx.hashB(alpha, sharedSecret); blinds[1] = blindingFactor; alphas[0] = alpha; _secrets[0] = sharedSecret; _asbTuples[0] = new byte[][] {alpha, sharedSecret, blindingFactor}; // round 1...(v-1) for (int i = 1; i < config.ROUTE_LENGTH; i++) { // base=previous alpha, exp=previous blind assert alphas[i-1] != null; assert blinds[i] != null; alpha = Sphinx.genSharedSecret(alphas[i-1], blinds[i]); // base=public key of mix, exp= all blinds (including x) sharedSecret = Sphinx.genSharedSecret(route.publicKeysOfMixes[i], blinds); blindingFactor = Sphinx.hashB(alpha, sharedSecret); blinds[i+1] = blindingFactor; alphas[i] = alpha; _secrets[i] = sharedSecret; _asbTuples[i] = new byte[][] { alpha, sharedSecret, blindingFactor }; } } private void computeFillerStrings() throws Exception { _fillerStrings[0] = new byte[0]; // phi_0 // phi_1 ... phi_(v-1) for (int i = 1; i < config.ROUTE_LENGTH; i++) { // previous phi padded with 2*_k zero bytes byte[] paddedPhi = Util.concatArrays(_fillerStrings[i-1], Sphinx.ZERO32); // The PRG generated with the shared secred s_(i-1) byte[] prg = Sphinx.rho(Sphinx.hashRho(_secrets[i-1], config.SECURITY_PARAMETER_SIZE), config.ROUTE_LENGTH, config.SECURITY_PARAMETER_SIZE); int min = (2 * (config.ROUTE_LENGTH - i) + 3) * config.SECURITY_PARAMETER_SIZE; int max = (2 * config.ROUTE_LENGTH + 3) * config.SECURITY_PARAMETER_SIZE; // exclusiv byte[] prgTruncated = Arrays.copyOfRange(prg, min, max); assert prgTruncated.length == paddedPhi.length; _fillerStrings[i] = Sphinx.xor(paddedPhi, prgTruncated); } } private void computeBetasGammas(byte[] id) throws Exception { byte[] random = new byte[(2 * (config.ROUTE_LENGTH - config.ROUTE_LENGTH) + 2) * config.SECURITY_PARAMETER_SIZE]; secureRandom.nextBytes(random); // TODO: wieso wird hier gepadded? hat header 32 byte platz für dest-id? // Destination + ID padded with random bytes byte[] paddedDestId = Util.concatArrays(id, random); // Destination + ID padded with random bytes byte[] prg = Sphinx.rho(Sphinx.hashRho(_secrets[config.ROUTE_LENGTH-1], config.SECURITY_PARAMETER_SIZE), config.ROUTE_LENGTH, config.SECURITY_PARAMETER_SIZE); // The PRG generated with the shared secred s_(v-1) byte[] prgTruncated = Arrays.copyOf(prg, (2 * (config.ROUTE_LENGTH - config.ROUTE_LENGTH) + 3) * config.SECURITY_PARAMETER_SIZE); assert paddedDestId.length == prgTruncated.length; // beta_v-1 byte[] beta = Util.concatArrays(Sphinx.xor(paddedDestId, prgTruncated), _fillerStrings[config.ROUTE_LENGTH-1]); _betas[config.ROUTE_LENGTH-1] = beta; // gamma_v-1 byte[] gamma = Sphinx.mu(Sphinx.hashMu(_secrets[config.ROUTE_LENGTH-1], config.SECURITY_PARAMETER_SIZE), beta, config.SECURITY_PARAMETER_SIZE); _gammas[config.ROUTE_LENGTH-1] = gamma; // betas and gammas for 0<=i<v-1 for (int i=config.ROUTE_LENGTH-2; i>=0; i--) { // the first (2*r-1)_k bytes of the previous beta byte[] betaTruncated = Arrays.copyOf(_betas[i+1], (2 * config.ROUTE_LENGTH - 1) * config.SECURITY_PARAMETER_SIZE); prg = Sphinx.rho(Sphinx.hashRho(_secrets[i], config.SECURITY_PARAMETER_SIZE), config.ROUTE_LENGTH, config.SECURITY_PARAMETER_SIZE); prgTruncated = Arrays.copyOf(prg, (2 * config.ROUTE_LENGTH + 1) * config.SECURITY_PARAMETER_SIZE); // the first (2*r+1)*_k bytes of the PRG beta = Sphinx.xor(Util.concatArrays(new byte[][] {route.mixIdsSphinx[i+1], gamma, betaTruncated}), prgTruncated); gamma = Sphinx.mu(Sphinx.hashMu(_secrets[i], config.SECURITY_PARAMETER_SIZE), beta, config.SECURITY_PARAMETER_SIZE); _betas[i] = beta; _gammas[i] = gamma; } } }