All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.getlime.security.powerauth.crypto.server.util.DataDigest Maven / Gradle / Ivy

There is a newer version: 1.9.0
Show newest version
/*
 * PowerAuth Crypto Library
 * Copyright 2018 Wultra s.r.o.
 *
 * 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 io.getlime.security.powerauth.crypto.server.util;

import io.getlime.security.powerauth.crypto.lib.generator.KeyGenerator;
import io.getlime.security.powerauth.crypto.lib.model.exception.CryptoProviderException;
import io.getlime.security.powerauth.crypto.lib.model.exception.GenericCryptoException;
import io.getlime.security.powerauth.crypto.lib.util.HMACHashUtilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * This is a helper class that provides utility methods for computing various data digests.
 *
 * @author Petr Dvorak, [email protected]
 */
public class DataDigest {

    private static final Logger logger = LoggerFactory.getLogger(DataDigest.class);

    /**
     * Data digest result.
     */
    public static class Result {

        private final String digest;
        private final byte[] salt;

        Result(String digest, byte[] salt) {
            this.digest = digest;
            this.salt = salt;
        }

        public String getDigest() {
            return digest;
        }

        public byte[] getSalt() {
            return salt;
        }

    }

    private static final int AUTHORIZATION_CODE_LENGTH_MIN = 4;
    private static final int AUTHORIZATION_CODE_LENGTH_MAX = 9;
    private static final int AUTHORIZATION_CODE_LENGTH = 8;

    private final HMACHashUtilities hmac = new HMACHashUtilities();

    private final int authorizationCodeLength;

    /**
     * Initializes the data digest instance that produces digest of length 8.
     */
    public DataDigest() {
        this.authorizationCodeLength = AUTHORIZATION_CODE_LENGTH;
    }

    /**
     * Initializes the data digest instance that produces digest of specified length. The length must be between 4 and 9.
     * The digest cannot be shorter than 4 due to lack of entropy in shorter codes. The digest cannot be longer than 9 digits
     * since the internal implementation uses int, with a 64 bit range.
     *
     * @param length Length of the resulting digest.
     * @throws GenericCryptoException In case the length is not in the allowed range - between 4 and 9 digits.
     */
    public DataDigest(int length) throws GenericCryptoException {
        if (length < AUTHORIZATION_CODE_LENGTH_MIN || length > AUTHORIZATION_CODE_LENGTH_MAX) {
            throw new GenericCryptoException("Invalid length of the data digest: " + length);
        }
        this.authorizationCodeLength = length;
    }

    /**
     * Data digest of the list with string elements. Data is first normalized (items concatenated
     * by '&' character), then a random key is generated and hash (HMAC-SHA256) is computed. Finally,
     * the resulting MAC is decimalized to the signature of a length 8 numeric digits.
     *
     * In case the digest could not be computed, null value is returned.
     *
     * @param items Items to be serialized into digest.
     * @return Digest fo provided data, including seed used to compute that digest.
     */
    public Result generateDigest(List items) {
        if (items.size() == 0) {
            return null;
        }
        byte[] operationData = String.join("&", items).getBytes(StandardCharsets.UTF_8);
        byte[] randomKey = new KeyGenerator().generateRandomBytes(16);
        try {
            byte[] otpHash = hmac.hash(randomKey, operationData);
            BigInteger otp = new BigInteger(otpHash).mod(BigInteger.TEN.pow(authorizationCodeLength));
            String digitFormat = "%" + String.format("%02d", authorizationCodeLength) + "d";
            String digest = String.format(digitFormat, otp);
            return new Result(digest, randomKey);
        } catch (GenericCryptoException | CryptoProviderException ex) {
            logger.warn(ex.getMessage(), ex);
            return null;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy