SHA-512 хеширование байтового массива в ColdFusion

Я использую ColdFusion 9

Ссылаясь на хорошие работы Бена Наделя на его блог, я попробовал

ucase(digestUtils.sha512(imageBinary))

Для хеширования SHA-512 я получаю то, что ужасно:

Метод sha512 не обнаружен. Либо нет методов с указанным именем метода и типами аргументов, либо метод sha512 перегружен типами аргументов, которые ColdFusion не может надежно расшифровать. ColdFusion обнаружил 0 методов, соответствующих указанным аргументам. Если это объект Java, и вы убедились, что метод существует, используйте функцию javacast, чтобы уменьшить двусмысленность.

Теперь я знаю, что sha512 действительно существует как метод, потому что я видел его здесь, но когда я выполняю

cfdump var="#digestUtils#"

Я получаю только:

md5(byte[])     byte[]
md5(java.lang.String)   byte[]
md5Hex(byte[])  java.lang.String
md5Hex(java.lang.String)    java.lang.String
sha(java.lang.String)   byte[]
sha(byte[])     byte[]
shaHex(java.lang.String)    java.lang.String
shaHex(byte[])  java.lang.String

Что случилось с другими методами? Думаю, мне нужно попробовать что-нибудь еще.

Посоветуйте, пожалуйста, раствор ColdFusion. Решение ColdFusion / Java тоже подойдет. Я пытаюсь написать приложение SSO, в котором сторонние парни передают мне параметры URL. Я успешно декодировал 1-й параметр, чтобы получить свой XML-пост. Теперь мне нужно взять 2-й параметр, который является полезной нагрузкой хэша, и пройти алгоритм, чтобы убедиться, что мой 1-й параметр не был изменен.

========= Здесь начинается редактирование: Хорошо, я попытался написать код еще раз, но безрезультатно.

Алгоритм звучит достаточно просто. Но попытки реализовать это убивают меня.

1. compute the hash string value of the XMLPost string above:
 a. convert the base64 salt string to a UTF-8 byte array.
 b. convert the base64 XML payload string to a UTF-8 byte array.
 c. create a new byte array consisting of the XML payload bytes from step b, appended with the salt bytes from step a.
 d. perform a SHA512 hash on the concatenated byte array from step c, which results in a hashed byte array.
 e. create a new byte array consisting of the hashed bytes from step d, appended with the salt bytes from step a.
 f. convert the result of step e to a base64-encoded string and should be the value of query string parameter "h" payload hash.

xmlPost был создан моими сторонними парнями как таковые: эта строка полезной нагрузки XML была преобразована в массив байтов UTF-8, который затем был преобразован в строку base-64. Результирующая строка base-64 - это значение моего xmlPost ниже.

Итак, я делаю это:

<code>
<cfset xmlPost = urlDecode("PD94bWwgdmVyc2lvbj0iMS4wIj8%2bPEVzdG9yZVNzb0N1c3RvbWVyIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzZD0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiPjxDdXN0b21lcklkPjExMjk0MDwvQ3VzdG9tZXJJZD48RGVhbGVyQ29kZT5OODg4ODg8L0RlYWxlckNvZGU%2bPFBvaW50QmFsYW5jZT4yODA8L1BvaW50QmFsYW5jZT48Rmlyc3ROYW1lPkZhaXRoPC9GaXJzdE5hbWU%2bPExhc3ROYW1lPkh1dHVsYTwvTGFzdE5hbWU%2bPC9Fc3RvcmVTc29DdXN0b21lcj4%3d") />
<cfset salt = "3dfjh674!MujErf98344@090" />
<cfset payload_hash = urlDecode("EtLDRJfcRESFKpY4OGZZnRSN2THqT%2bEelzOuXVU06jotd2kE4yKnlYay7BqyAdcUSATRgSMaHxZa6uBqKKd9rjNkZmpoNjc0IU11akVyZjk4MzQ0QDA5MA%3d%3d") />

<cfset strXML = ToString( ToBinary( xmlpost ) ) /> <!--- to get actual XML --->

<!--- base64 encoding returns a byte array --->
<cfset saltByteArray = toBase64( salt, "utf-8" )  /> 
<cfset xmlpostByteArray = toBase64( xmlPost, "utf-8" ) />
<!--- append salt to xmlpost --->
<cfset xmlpostsaltByteArray = xmlpostByteArray & saltByteArray />

<!--- now let us perform a sha512 hash on this concatenated byte array --->
<cfscript>
// Create an instance of our DigestUtils class
digestUtils = createObject("java","org.apache.commons.codec.digest.DigestUtils");
// I hash a byte array using the given algorithm and return a
// 32-character Hexadecimal string. Home-made hash function for CF9 and earlier
function hashBytes( bytes, algorithm = "SHA-512" ){
    // Get our instance of the digest algorithm that we'll use
    // to hash the byte array.
    var messageDigest = createObject( "java", "java.security.MessageDigest" ).getInstance( javaCast( "string", algorithm ) );

    // Get the digest for the given byte array. This returns the
    // digest (i.e., hash) in byte-array format.
    var digest = messageDigest.digest( bytes );

    // Now that we have our digested byte array (i.e., our hash as another byte
    // array), we have to convert that into a HEX string. So, we'll need a HEX buffer.
    var hexBuffer = [];

    // Each integer in the byte digest needs to be converted into
    // a HEX character (with possible leading zero).
    for (byte =1 ;byte LTE ArrayLen(digest);byte = byte + 1) {
    //for ( var byte in digest){
        // Get the hex value for this byte. When converting the
        // byte, only use the right-most 8 bits (last 8 bits of the integer)
        // otherwise the sign of the byte can create oddities

        var tail = bitAnd( 255, byte );

        // Get the hex-encoding of the byte.
        var hex = ucase( formatBaseN( tail, 16 ) );

        // In order to make sure that all of the HEX characters
        // are two-digits, we have to prepend a zero for any
        // value that was originally LTE to 16 (the largest value
        // that won't result in two HEX characters).
        arrayAppend( hexBuffer, (tail <= 16 ? ("0" & hex) : hex) );
    }

    // Return the flattened character buffer.
    return( arrayToList( hexBuffer, "" ) );
}

// Get the hash of the byte array using our hashBytes() function
hashByteArray = hashBytes( xmlpostsaltByteArray );  
</cfscript>


<!--- The hashByteArray is in HEX format now. Convert to binary --->
<!--- You must binary decode the hashed string before converting it to binary --->
<cfset hashByteArray = toBase64( BinaryDecode( hashByteArray, 'HEX' ) ) />

<!--- The final step is to append this new hashbytearray with the salt byte array --->

<cfset hashByteArray = hashByteArray & saltByteArray />

<!--- now convert this value to a base64 encoded string --->

<cfset hashByteArray2 = toBase64( hashByteArray )/>

Here is what I get for my strXML variable:

Actual xml structure converted from base 64 to string:
<?xml version="1.0"?><EstoreSsoCustomer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><CustomerId>112940</CustomerId><DealerCode>N88888</DealerCode><PointBalance>280</PointBalance><FirstName>Faith</FirstName><LastName>Hutula</LastName></EstoreSsoCustomer>  

Последнее значение hasByteArray2 даже отдаленно не похоже на payload_hash.

Я делаю это впервые, и мое понимание хеширования, байтовых массивов и преобразования символов улетучилось несколько десятилетий назад.

Что я делаю неправильно?

Спасибо, Фейт Слоун


person Faith Sloan    schedule 25.05.2012    source источник


Ответы (1)


DigestUtils .sha512 был добавлен в версию 1.4. ColdFusion 9 использует старую версию 1.3. Вот почему метод не найден.

Используйте другую функцию, основанную на MessageDigest. Просто убедитесь, что вы передаете правильный алгоритм, то есть:

    imageHash = hashBytes( imageBinary, "SHA-512" );

ОБНОВЛЕНИЕ. Исходя из обновленного кода, некоторые инструкции могут вводить в заблуждение. Я считаю, что они просто означают декодирование строк xml и salt из их заданной кодировки (base64 и utf-8) в байтовые массивы, а не строки:

    // note: salt value has invalid characters for base64
    // assuming it is a plain utf-8 string
    saltArray = charsetDecode(salt, "utf-8");
    xmlByteArray = binaryDecode(xmlPost, "base64");

Затем объедините два двоичных массива (см. Настраиваемую функцию)

    mergedBytes = mergeArrays( xmlByteArray, saltArray );

Вычислите хеш нового байтового массива:

    messageDigest = createObject( "java", "java.security.MessageDigest" );
    messageDigest = messageDigest.getInstance( javaCast( "string", "SHA-512") );
    hashedByteArray = messageDigest.digest( javacast("byte[]", mergedBytes) );

Снова объедините массивы:

    mergedBytes = mergeArrays( hashedByteArray, saltArray);

Наконец преобразуйте двоичный файл в base64 и сравните:

    calculatedPayload = binaryEncode( javacast("byte[]", mergedBytes), "base64");

    // check results
    arePayloadsEqual = compare(calculatedPayload, payload_hash) eq 0;
    WriteDump("arePayloadsEqual="& arePayloadsEqual);
    WriteDump("calculatedPayload="& calculatedPayload);
    WriteDump("payload_hash="& payload_hash);

Примечание: BinaryDecode/CharsetDecode возвращают массивы Java. В отличие от массивов CF, они неизменяемы (т.е. не могут быть изменены). Итак, удобный addAll (.. ) уловка здесь не сработает.

    // merge immutable arrays the long way
    function mergeArrays( array1, array2 ){
        var i = 0;
        var newArray = [];
        for (i = 1; i <= arrayLen(arguments.array1); i++) {
            arrayAppend(newArray, arguments.array1[i]);
        }
        for (i = 1; i <= arrayLen(arguments.array2); i++) {
            arrayAppend(newArray, arguments.array2[i]);
        }
        return newArray;
    }   
person Leigh    schedule 25.05.2012
comment
Я пытался и пытался, но безуспешно, чтобы добиться совпадения значений хэша. См. Отредактированный пост выше. - person Faith Sloan; 30.05.2012
comment
Пока не вижу правок. Сообщите мне, когда опубликуете образцы значений. - person Leigh; 30.05.2012
comment
Примеры значений находятся в коде. xmlpost, salt и payload_hash. мой вычисленный хеш должен быть таким же, как payload_hash. Но это не так. Я также показал вам декодированный мной strXML, и он подходит для xmlpost. Моя проблема - хеширование. - person Faith Sloan; 31.05.2012
comment
@FaithSloan - Спасибо за размещение кода. Теперь я вижу проблему. См. Мой обновленный ответ. - person Leigh; 31.05.2012
comment
Ли, ты ЧУДЕСНЫЙ! Я пытался проголосовать за ваш ответ, НО я новичок в этом заведении и у меня недостаточно очков репутации. Большое Вам спасибо! Когда я наберу достаточно очков, Я вернусь, чтобы проголосовать за ваш ответ как ОТВЕТ! - person Faith Sloan; 31.05.2012
comment
Спасибо, рад, что смог помочь :) - person Leigh; 31.05.2012