{"record":{"id":"9fba1ee120bb08d8","repo":"nathanmarz/storm","slug":"blowfish-encryption-key-invalid","errorCode":null,"errorMessage":"Blowfish encryption key invalid","messagePattern":"Blowfish encryption key invalid","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"storm-core/src/jvm/backtype/storm/security/serialization/BlowfishTupleSerializer.java","lineNumber":60,"sourceCode":"     * The secret key (if any) for data encryption by blowfish payload serialization factory (BlowfishSerializationFactory). \n     * You should use in via \"storm -c topology.tuple.serializer.blowfish.key=YOURKEY -c topology.tuple.serializer=backtype.storm.security.serialization.BlowfishTupleSerializer jar ...\".\n     */\n    public static String SECRET_KEY = \"topology.tuple.serializer.blowfish.key\";\n    private static final Logger LOG = Logger.getLogger(BlowfishTupleSerializer.class);\n    private BlowfishSerializer _serializer;\n\n    public BlowfishTupleSerializer(Kryo kryo, Map storm_conf) {\n        String encryption_key = null;\n        try {\n            encryption_key = (String)storm_conf.get(SECRET_KEY);\n            LOG.debug(\"Blowfish serializer being constructed ...\");\n            if (encryption_key == null) {\n                throw new RuntimeException(\"Blowfish encryption key not specified\");\n            }\n            byte[] bytes =  Hex.decodeHex(encryption_key.toCharArray());\n            _serializer = new BlowfishSerializer(new ListDelegateSerializer(), bytes);\n        } catch (org.apache.commons.codec.DecoderException ex) {\n            throw new RuntimeException(\"Blowfish encryption key invalid\", ex);\n        }\n    }\n\n    @Override\n    public void write(Kryo kryo, Output output, ListDelegate object) {\n        _serializer.write(kryo, output, object);\n    }\n\n    @Override\n    public ListDelegate read(Kryo kryo, Input input, Class<ListDelegate> type) {\n        return (ListDelegate)_serializer.read(kryo, input, type);\n    }\n\n    /**\n     * Produce a blowfish key to be used in \"Storm jar\" command\n     */\n    public static void main(String[] args) {\n        try{","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/backtype/storm/security/serialization/BlowfishTupleSerializer.java#L42-L78","documentation":"BlowfishTupleSerializer decodes the configured encryption key from a hex string with Apache Commons Codec's Hex.decodeHex. If the configured key is not valid hexadecimal (odd length or non-hex characters), decodeHex throws DecoderException and the constructor wraps it in this RuntimeException('Blowfish encryption key invalid', ex).","triggerScenarios":"Setting the Blowfish secret-key config value to a non-hex string (e.g. plain text 'mysecretkey', a base64 key, or a key with stray whitespace/quotes) when BlowfishTupleSerializer is constructed with that storm_conf.","commonSituations":"Pasting a YAML string with accidental quotes or trailing spaces into storm.yaml; using a passphrase instead of a hex-encoded key; copying a key with a trailing newline from a CLI generator; accidentally generating an odd-length hex string by hand.","solutions":["Replace the key with a valid even-length hex string (characters 0-9a-f only), e.g. generate one with 'openssl rand -hex 16'.","Strip quotes, whitespace, and newlines from the value in storm.yaml.","Keep the key at a reasonable length ( Blowfish supports 32–448 bit keys, so 8–56 hex-decoded bytes).","Ensure the same corrected key is deployed to all nodes so workers agree on the key."],"exampleFix":"// storm.yaml before (passphrase, not hex)\ntopology.tuple.secret.key: \"my secret pass phrase\"\n// after\ntopology.tuple.secret.key: \"3f8a1c9d2b7e4f6a1c9d2b7e4f6a1c9d\"","handlingStrategy":"validation","validationCode":"String key = (String) stormConf.get(\"topology.tuple.secret.key\");\nif (key != null && (!key.matches(\"[0-9a-fA-F]+\") || key.length() % 2 != 0)) {\n    throw new IllegalArgumentException(\"Blowfish secret key must be a valid even-length hex string\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    byte[] bytes = Hex.decodeHex(key.toCharArray());\n    // proceed with key\n} catch (org.apache.commons.codec.DecoderException e) {\n    throw new IllegalArgumentException(\"Configured Blowfish key is not valid hex: \" + e.getMessage(), e);\n}","preventionTips":["Always generate the key with a hex-producing tool (openssl rand -hex) instead of hand-writing one","Trim whitespace and remove surrounding quotes when embedding the key in storm.yaml","Hex-decode the configured key in a deployment smoke test before rolling out","Keep key length in the Blowfish-legal range (8–56 bytes after decoding)"],"tags":["encryption","kryo","configuration","hex","storm"],"backgroundTag":"invalid-config-value","analyzedSha":"cdb116e942666973bc4eaa0df098d5bab82739e7","analyzedAt":"2026-09-12T14:30:00.714Z","contentChangedAt":"2026-09-12T14:30:00.714Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}