Last active
October 7, 2026 02:18
-
-
Save sloanlance/af3b85bb3647a61c2617db3279975003 to your computer and use it in GitHub Desktop.
Apigee crypto SHA function tests — Testing to see which `crypto` SHA functions are available in the Google Apigee environment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Apigee crypto SHA function tests |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ============================================================ | |
| // TEMPORARY DIAGNOSTIC. Remove before production. | |
| // | |
| // Probes Apigee's JS crypto object against known test vectors. | |
| // Verdicts are derived from the recorded results, so a missing | |
| // test reports 'TEST MISSING' rather than a false negative. | |
| // ============================================================ | |
| var INPUT = 'abc'; | |
| // Standard published vectors for the ASCII string "abc". | |
| var EXPECTED = { | |
| md5: '900150983cd24fb0d6963f7d28e17f72', | |
| sha1: 'a9993e364706816aba3e25717850c26c9cd0d89d', | |
| sha256: 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', | |
| sha512: 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a' + | |
| '2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f' | |
| }; | |
| // SHA-256 of the empty string. | |
| var SHA256_EMPTY = | |
| 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'; | |
| var results = {}; | |
| // Records one probe. 'expected' may be null for informational tests. | |
| function record(label, expected, fn) { | |
| var entry = {}; | |
| try { | |
| var out = fn(); | |
| entry.value = (out === null || out === undefined) | |
| ? '<null/undefined>' | |
| : String(out); | |
| } catch (e) { | |
| entry.error = 'ERROR: ' + (e.message || String(e)); | |
| } | |
| if (entry.value !== undefined) { | |
| entry.length = entry.value.length; | |
| entry.isLowerHex = /^[0-9a-f]+$/.test(entry.value); | |
| } | |
| if (expected !== null && expected !== undefined) { | |
| entry.expected = String(expected); | |
| if (entry.error) { | |
| entry.match = 'error'; | |
| } else if (entry.value === entry.expected) { | |
| entry.match = 'exact'; | |
| } else if (entry.value.toLowerCase() === entry.expected.toLowerCase()) { | |
| entry.match = 'case-insensitive-only'; | |
| } else { | |
| entry.match = 'MISMATCH'; | |
| } | |
| } else { | |
| entry.match = 'informational'; | |
| } | |
| results[label] = entry; | |
| } | |
| // Reads a verdict back out of 'results'. Guards against typo'd labels. | |
| function matchOf(label) { | |
| if (!Object.prototype.hasOwnProperty.call(results, label)) { | |
| return 'TEST MISSING (' + label + ')'; | |
| } | |
| return results[label].match || 'no-verdict'; | |
| } | |
| // ---------- environment ---------------------------------------------------- | |
| results['_env.crypto.typeof'] = { value: typeof crypto, match: 'informational' }; | |
| if (typeof crypto === 'undefined') { | |
| results['_env.fatal'] = { | |
| value: 'crypto object is not available', | |
| match: 'informational' | |
| }; | |
| } else { | |
| var members = []; | |
| var types = []; | |
| try { | |
| for (var k in crypto) { | |
| members.push(k); | |
| try { types.push(k + ':' + (typeof crypto[k])); } | |
| catch (e1) { types.push(k + ':<unreadable>'); } | |
| } | |
| } catch (e2) { | |
| members.push('<not enumerable>'); | |
| } | |
| results['_env.members'] = { value: members.join(','), match: 'informational' }; | |
| results['_env.memberTypes'] = { value: types.join(','), match: 'informational' }; | |
| // ---------- core: digest() hex, all four algorithms -------------------- | |
| record('md5.digest', EXPECTED.md5, function () { | |
| var h = crypto.getMD5(); h.update(INPUT); return h.digest(); | |
| }); | |
| record('sha1.digest', EXPECTED.sha1, function () { | |
| var h = crypto.getSHA1(); h.update(INPUT); return h.digest(); | |
| }); | |
| record('sha256.digest', EXPECTED.sha256, function () { | |
| var h = crypto.getSHA256(); h.update(INPUT); return h.digest(); | |
| }); | |
| record('sha512.digest', EXPECTED.sha512, function () { | |
| var h = crypto.getSHA512(); h.update(INPUT); return h.digest(); | |
| }); | |
| // ---------- alternate encodings (informational; App needs hex) ----- | |
| record('sha256.digest64', null, function () { | |
| var h = crypto.getSHA256(); h.update(INPUT); return h.digest64(); | |
| }); | |
| record('sha512.digest64', null, function () { | |
| var h = crypto.getSHA512(); h.update(INPUT); return h.digest64(); | |
| }); | |
| // ---------- update() semantics ---------------------------------------- | |
| // If update() appends, two calls should equal the single-call digest. | |
| record('sha256.updateSplit', EXPECTED.sha256, function () { | |
| var h = crypto.getSHA256(); h.update('a'); h.update('bc'); return h.digest(); | |
| }); | |
| // Three-part split, to confirm it is not just a two-call special case. | |
| record('sha512.updateSplit3', EXPECTED.sha512, function () { | |
| var h = crypto.getSHA512(); | |
| h.update('a'); h.update('b'); h.update('c'); | |
| return h.digest(); | |
| }); | |
| // digest() with no update() at all. | |
| record('sha256.noUpdate', SHA256_EMPTY, function () { | |
| var h = crypto.getSHA256(); return h.digest(); | |
| }); | |
| // update('') then digest(). | |
| record('sha256.emptyUpdate', SHA256_EMPTY, function () { | |
| var h = crypto.getSHA256(); h.update(''); return h.digest(); | |
| }); | |
| // ---------- object lifecycle ------------------------------------------ | |
| // Two independent objects, same input: both must be correct. | |
| record('sha512.freshA', EXPECTED.sha512, function () { | |
| var h = crypto.getSHA512(); h.update(INPUT); return h.digest(); | |
| }); | |
| record('sha512.freshB', EXPECTED.sha512, function () { | |
| var h = crypto.getSHA512(); h.update(INPUT); return h.digest(); | |
| }); | |
| // Calling digest() twice on one object: stable, reset, or error? | |
| record('sha256.digestTwice', null, function () { | |
| var h = crypto.getSHA256(); | |
| h.update(INPUT); | |
| var first = h.digest(); | |
| var second = h.digest(); | |
| return 'first=' + first + ' second=' + second + | |
| ' same=' + (first === second); | |
| }); | |
| // Reusing an object after digest(): does state carry over? | |
| record('sha256.reuseAfterDigest', null, function () { | |
| var h = crypto.getSHA256(); | |
| h.update(INPUT); | |
| var first = h.digest(); | |
| h.update(INPUT); | |
| var second = h.digest(); | |
| return 'first=' + first + ' second=' + second + | |
| ' secondIsAbcHash=' + (second === EXPECTED.sha256); | |
| }); | |
| // ---------- getHash() alternate factory (informational) --------------- | |
| record('getHash.SHA-512', null, function () { | |
| var h = crypto.getHash('SHA-512'); h.update(INPUT); return h.digest(); | |
| }); | |
| record('getHash.SHA512', null, function () { | |
| var h = crypto.getHash('SHA512'); h.update(INPUT); return h.digest(); | |
| }); | |
| // ---------- App usage pattern ------------------------------------- | |
| // Shape only; these are not real credentials. | |
| var FAKE_SESSION_ID = 'ZjM0NWY2NzhhYmNkZWYwMTIzNDU2Nzg5YWJjZGVmMDF8MTAwfA=='; | |
| var FAKE_TOKEN = '0123456789abcdef0123456789abcdef'; | |
| record('app.sha256.concat', null, function () { | |
| var h = crypto.getSHA256(); h.update(FAKE_SESSION_ID + FAKE_TOKEN); return h.digest(); | |
| }); | |
| record('app.sha512.concat', null, function () { | |
| var h = crypto.getSHA512(); h.update(FAKE_SESSION_ID + FAKE_TOKEN); return h.digest(); | |
| }); | |
| // Same inputs via split updates: must match the concatenated form. | |
| record('app.sha512.split', null, function () { | |
| var h = crypto.getSHA512(); | |
| h.update(FAKE_SESSION_ID); h.update(FAKE_TOKEN); | |
| var split = h.digest(); | |
| var h2 = crypto.getSHA512(); | |
| h2.update(FAKE_SESSION_ID + FAKE_TOKEN); | |
| return 'split=' + split + ' matchesConcat=' + (split === h2.digest()); | |
| }); | |
| } | |
| // ---------- verdicts (derived from the records above) ---------------------- | |
| var verdicts = {}; | |
| verdicts['md5.digest'] = matchOf('md5.digest'); | |
| verdicts['sha1.digest'] = matchOf('sha1.digest'); | |
| verdicts['SHA256 hex digest'] = matchOf('sha256.digest'); | |
| verdicts['SHA512 hex digest'] = matchOf('sha512.digest'); | |
| verdicts['update() appends (256)'] = matchOf('sha256.updateSplit'); | |
| verdicts['update() appends (512)'] = matchOf('sha512.updateSplit3'); | |
| verdicts['fresh objects A'] = matchOf('sha512.freshA'); | |
| verdicts['fresh objects B'] = matchOf('sha512.freshB'); | |
| // Collect every failure across all tests that had an expectation. | |
| var failures = []; | |
| for (var label in results) { | |
| if (!Object.prototype.hasOwnProperty.call(results, label)) { continue; } | |
| var m = results[label].match; | |
| if (m === 'MISMATCH' || m === 'error' || m === 'case-insensitive-only') { | |
| failures.push(label + '=' + m); | |
| } | |
| } | |
| // Overall go/no-go for the App appToken use case. | |
| var sha256ok = (matchOf('sha256.digest') === 'exact'); | |
| var sha512ok = (matchOf('sha512.digest') === 'exact'); | |
| verdicts['_OVERALL'] = | |
| (sha256ok && sha512ok) | |
| ? 'GO: SHA-256 and SHA-512 both produce correct lowercase hex via digest()' | |
| : 'NO-GO: sha256=' + matchOf('sha256.digest') + | |
| ' sha512=' + matchOf('sha512.digest'); | |
| verdicts['_failures'] = failures.length ? failures.join(' | ') : 'none'; | |
| context.setVariable('cryptocheck.report', | |
| JSON.stringify({ verdicts: verdicts, results: results }, null, 2)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "verdicts": { | |
| "md5.digest": "exact", | |
| "sha1.digest": "exact", | |
| "SHA256 hex digest": "exact", | |
| "SHA512 hex digest": "exact", | |
| "update() appends (256)": "exact", | |
| "update() appends (512)": "exact", | |
| "fresh objects A": "exact", | |
| "fresh objects B": "exact", | |
| "_OVERALL": "GO: SHA-256 and SHA-512 both produce correct lowercase hex via digest()", | |
| "_failures": "none" | |
| }, | |
| "results": { | |
| "_env.crypto.typeof": { | |
| "value": "object", | |
| "match": "informational" | |
| }, | |
| "_env.members": { | |
| "value": "getMD5,getSHA1,getSHA256,getSHA512,getHash,base64,wsSecRsaSign,wsSecRsaValidate,asBytes,dateFormat", | |
| "match": "informational" | |
| }, | |
| "_env.memberTypes": { | |
| "value": "getMD5:function,getSHA1:function,getSHA256:function,getSHA512:function,getHash:function,base64:function,wsSecRsaSign:function,wsSecRsaValidate:function,asBytes:function,dateFormat:function", | |
| "match": "informational" | |
| }, | |
| "md5.digest": { | |
| "value": "900150983cd24fb0d6963f7d28e17f72", | |
| "length": 32, | |
| "isLowerHex": true, | |
| "expected": "900150983cd24fb0d6963f7d28e17f72", | |
| "match": "exact" | |
| }, | |
| "sha1.digest": { | |
| "value": "a9993e364706816aba3e25717850c26c9cd0d89d", | |
| "length": 40, | |
| "isLowerHex": true, | |
| "expected": "a9993e364706816aba3e25717850c26c9cd0d89d", | |
| "match": "exact" | |
| }, | |
| "sha256.digest": { | |
| "value": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", | |
| "length": 64, | |
| "isLowerHex": true, | |
| "expected": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", | |
| "match": "exact" | |
| }, | |
| "sha512.digest": { | |
| "value": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "length": 128, | |
| "isLowerHex": true, | |
| "expected": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "match": "exact" | |
| }, | |
| "sha256.digest64": { | |
| "value": "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=", | |
| "length": 44, | |
| "isLowerHex": false, | |
| "match": "informational" | |
| }, | |
| "sha512.digest64": { | |
| "value": "3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw==", | |
| "length": 88, | |
| "isLowerHex": false, | |
| "match": "informational" | |
| }, | |
| "sha256.updateSplit": { | |
| "value": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", | |
| "length": 64, | |
| "isLowerHex": true, | |
| "expected": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", | |
| "match": "exact" | |
| }, | |
| "sha512.updateSplit3": { | |
| "value": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "length": 128, | |
| "isLowerHex": true, | |
| "expected": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "match": "exact" | |
| }, | |
| "sha256.noUpdate": { | |
| "value": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | |
| "length": 64, | |
| "isLowerHex": true, | |
| "expected": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | |
| "match": "exact" | |
| }, | |
| "sha256.emptyUpdate": { | |
| "value": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | |
| "length": 64, | |
| "isLowerHex": true, | |
| "expected": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | |
| "match": "exact" | |
| }, | |
| "sha512.freshA": { | |
| "value": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "length": 128, | |
| "isLowerHex": true, | |
| "expected": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "match": "exact" | |
| }, | |
| "sha512.freshB": { | |
| "value": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "length": 128, | |
| "isLowerHex": true, | |
| "expected": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "match": "exact" | |
| }, | |
| "sha256.digestTwice": { | |
| "value": "first=ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad second=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 same=false", | |
| "length": 153, | |
| "isLowerHex": false, | |
| "match": "informational" | |
| }, | |
| "sha256.reuseAfterDigest": { | |
| "value": "first=ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad second=ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad secondIsAbcHash=true", | |
| "length": 163, | |
| "isLowerHex": false, | |
| "match": "informational" | |
| }, | |
| "getHash.SHA-512": { | |
| "value": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "length": 128, | |
| "isLowerHex": true, | |
| "match": "informational" | |
| }, | |
| "getHash.SHA512": { | |
| "value": "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", | |
| "length": 128, | |
| "isLowerHex": true, | |
| "match": "informational" | |
| }, | |
| "app.sha256.concat": { | |
| "value": "11327fe57b85813a7b6f4b69d10fb90678315f1413ce6ed6379c7c44467ee3c0", | |
| "length": 64, | |
| "isLowerHex": true, | |
| "match": "informational" | |
| }, | |
| "app.sha512.concat": { | |
| "value": "dc3fd032ed73ba15a05dc67e6db166be448ff5c78e243b0547064614047523de428b95f85c6f0ee074f7a4158c0f5f6c597064ccc91b15dad38e8249fb940a08", | |
| "length": 128, | |
| "isLowerHex": true, | |
| "match": "informational" | |
| }, | |
| "app.sha512.split": { | |
| "value": "split=dc3fd032ed73ba15a05dc67e6db166be448ff5c78e243b0547064614047523de428b95f85c6f0ee074f7a4158c0f5f6c597064ccc91b15dad38e8249fb940a08 matchesConcat=true", | |
| "length": 153, | |
| "isLowerHex": false, | |
| "match": "informational" | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment