{"record":{"id":"2f3792a91fd4e168","repo":"apache/hadoop","slug":"wrong-key-length-required-options-getbitlength","errorCode":null,"errorMessage":"Wrong key length. Required ${options.getBitLength()}, but got ${8 * material.length}","messagePattern":"Wrong key length\\. Required (.+?), but got (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/JavaKeyStoreProvider.java","lineNumber":451,"sourceCode":"  @Override\n  public KeyVersion createKey(String name, byte[] material,\n                               Options options) throws IOException {\n    Preconditions.checkArgument(name.equals(StringUtils.toLowerCase(name)),\n        \"Uppercase key names are unsupported: %s\", name);\n    writeLock.lock();\n    try {\n      try {\n        if (keyStore.containsAlias(name) || cache.containsKey(name)) {\n          throw new IOException(\"Key \" + name + \" already exists in \" + this);\n        }\n      } catch (KeyStoreException e) {\n        throw new IOException(\"Problem looking up key \" + name + \" in \" + this,\n            e);\n      }\n      Metadata meta = new Metadata(options.getCipher(), options.getBitLength(),\n          options.getDescription(), options.getAttributes(), new Date(), 1);\n      if (options.getBitLength() != 8 * material.length) {\n        throw new IOException(\"Wrong key length. Required \" +\n            options.getBitLength() + \", but got \" + (8 * material.length));\n      }\n      cache.put(name, meta);\n      String versionName = buildVersionName(name, 0);\n      return innerSetKeyVersion(name, versionName, material, meta.getCipher());\n    } finally {\n      writeLock.unlock();\n    }\n  }\n\n  @Override\n  public void deleteKey(String name) throws IOException {\n    writeLock.lock();\n    try {\n      Metadata meta = getMetadata(name);\n      if (meta == null) {\n        throw new IOException(\"Key \" + name + \" does not exist in \" + this);\n      }","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/key/JavaKeyStoreProvider.java#L433-L469","documentation":"Thrown by JavaKeyStoreProvider.createKey(String, byte[], Options) when the supplied key material does not match the requested key size: the provider enforces options.getBitLength() == 8 * material.length so the bytes stored in the JCEKS keystore always agree with the Metadata recorded for the key. The check runs before the cache or keystore is touched, so a rejected create leaves no partial state.","triggerScenarios":"Calling createKey with Options built with setBitLength(256) but passing a 16-byte (128-bit) array; passing 32 random bytes while Options still carries the default bit length; hand-rolled SecureRandom fills sized independently of the options; reusing material generated for a different key size.","commonSituations":"Copy-pasted sample code that allocates 16 bytes but sets 256 bits; migrating from 128-bit to 256-bit AES without updating the generation code; unit tests using fixed strings like '0123456789abcdef0' of arbitrary length as material.","solutions":["Size the material to exactly options.getBitLength() / 8 bytes (e.g. 32 bytes for 256-bit)","Prefer KeyProvider.generateKey(bitLength, cipher) or the one-arg createKey(name, options) overload, which build correctly sized material for you","Add a caller-side assertion material.length == options.getBitLength() / 8 before calling so you fail with your own message"],"exampleFix":"// before\nOptions opts = new Options(conf).setCipher(\"AES\").setBitLength(256);\nbyte[] material = new byte[16]; // 128 bits, mismatch\nprovider.createKey(\"dek\", material, opts);\n\n// after\nOptions opts = new Options(conf).setCipher(\"AES\").setBitLength(256);\nbyte[] material = new byte[opts.getBitLength() / Byte.SIZE];\nnew SecureRandom().nextBytes(material);\nprovider.createKey(\"dek\", material, opts);","handlingStrategy":"validation","validationCode":"if (material == null || 8 * material.length != options.getBitLength()) {\n  throw new IllegalArgumentException(\"material is \"\n      + (material == null ? 0 : 8 * material.length)\n      + \" bits, options require \" + options.getBitLength());\n}\nprovider.createKey(name, material, options);","typeGuard":null,"tryCatchPattern":"catch (IOException e) { if (e.getMessage() != null && e.getMessage().startsWith(\"Wrong key length\")) { // regenerate material at options.getBitLength()/8 and retry once } else { throw e; } }","preventionTips":["Always derive material size from options.getBitLength()/8","Use generateKey()/createKey(name, options) overloads instead of hand-built material","In tests, build material via KeyProvider.generateKey so length stays consistent"],"tags":["java","hadoop","key-provider","key-management","validation"],"backgroundTag":"key-length-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}