/*
* Licensed to Crate under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership. Crate licenses this file
* to you 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.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial
* agreement.
*/
package io.crate.operation.scalar.string;
import io.crate.metadata.FunctionIdent;
import io.crate.metadata.FunctionInfo;
import io.crate.operation.scalar.ScalarFunctionModule;
import io.crate.operation.scalar.UnaryScalar;
import io.crate.types.DataType;
import io.crate.types.DataTypes;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.hash.MessageDigests;
import java.security.DigestException;
import java.security.MessageDigest;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
public final class HashFunctions {
private static final List<DataType> SUPPORTED_INPUT_TYPE = Collections.singletonList((DataTypes.STRING));
private enum HashMethod {
MD5(MessageDigests.md5()),
SHA1(MessageDigests.sha1());
private final MessageDigest messageDigest;
HashMethod(MessageDigest method) {
this.messageDigest = method;
}
public BytesRef digest(BytesRef input) {
byte[] digest = new byte[messageDigest.getDigestLength()];
messageDigest.update(input.bytes, input.offset, input.length);
try {
messageDigest.digest(digest, 0, digest.length);
} catch (DigestException e) {
throw new RuntimeException("Error computing digest.", e);
}
return new BytesRef(convertToHex(digest));
}
/**
* Converts a byte array into an ASCII/UTF-8 hex encoded string.
* @param input the input array to transform to a hex string
* @return The resulting ASCII/UTF-8 encoded byte array which holds the hex string.
*/
private static byte[] convertToHex(byte[] input) {
byte[] hexString = new byte[input.length << 1];
for (int temp, i = 0; i < input.length; i++) {
temp = (input[i] >> 4) & 0x0F;
hexString[2*i] = (byte) (temp < 10 ? temp + '0' : temp + 'W');
temp = input[i] & 0x0F;
hexString[2*i+1] = (byte) (temp < 10 ? temp + '0' : temp + 'W');
}
return hexString;
}
}
private static void register(ScalarFunctionModule module, String name, Function<BytesRef, BytesRef> func) {
FunctionIdent ident = new FunctionIdent(name, SUPPORTED_INPUT_TYPE);
module.register(new UnaryScalar<>(new FunctionInfo(ident, DataTypes.STRING), func));
}
public static void register(ScalarFunctionModule module) {
register(module, "md5", HashMethod.MD5::digest);
register(module, "sha1", HashMethod.SHA1::digest);
}
}