jorabin / KeePassJava2

Java API for KeePass Password Databases - Read/Write 2.x (File versions 3 and 4), Read 1.x
Apache License 2.0
251 stars 70 forks source link

UnrecognizedPropertyException: Unrecognized field "Item" when using JacksonDatabase or SimpleDatabase #70

Open lordgreg opened 1 day ago

lordgreg commented 1 day ago

We have a kdbx encrypted with password, using KDBX db v2.x

ls foobar.kdbx
 foobar.kdbx
❯ file foobar.kdbx
foobar.kdbx: Keepass password database 2.x KDBX

Opening the file with SimpleDatabase:

Exception in thread "main" java.lang.IllegalStateException: org.simpleframework.xml.core.ElementException: Element 'Item' does not have a match in class org.linguafranca.pwdb.kdbx.simple.model.KeePassFile$CustomData at line 35
    at org.linguafranca.pwdb.kdbx.simple.SimpleSerializableDatabase.load(SimpleSerializableDatabase.java:80)
    at org.linguafranca.pwdb.kdbx.simple.SimpleSerializableDatabase.load(SimpleSerializableDatabase.java:41)
    at org.linguafranca.pwdb.kdbx.KdbxStreamFormat.load(KdbxStreamFormat.java:65)
    at org.linguafranca.pwdb.kdbx.simple.SimpleDatabase.load(SimpleDatabase.java:91)
    at FOO.keepass2helm.Example.main(Example.kt:22)
    at FOO.keepass2helm.ExampleKt.main(Example.kt:77)
    Suppressed: org.bouncycastle.crypto.io.InvalidCipherTextIOException: Error finalising cipher
        at org.bouncycastle.crypto.io.CipherInputStream.finaliseCipher(Unknown Source)
        at org.bouncycastle.crypto.io.CipherInputStream.close(Unknown Source)
        at java.base/java.util.zip.InflaterInputStream.close(InflaterInputStream.java:231)
        at java.base/java.util.zip.GZIPInputStream.close(GZIPInputStream.java:136)
        at org.linguafranca.pwdb.kdbx.KdbxStreamFormat.load(KdbxStreamFormat.java:76)
        ... 3 more
    Caused by: org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
        at org.bouncycastle.crypto.paddings.PKCS7Padding.padCount(Unknown Source)
        at org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher.doFinal(Unknown Source)
        ... 8 more
Caused by: org.simpleframework.xml.core.ElementException: Element 'Item' does not have a match in class org.linguafranca.pwdb.kdbx.simple.model.KeePassFile$CustomData at line 35
    at org.simpleframework.xml.core.Composite.readElement(Composite.java:527)
    at org.simpleframework.xml.core.Composite.readElements(Composite.java:445)
    at org.simpleframework.xml.core.Composite.access$400(Composite.java:59)
    at org.simpleframework.xml.core.Composite$Builder.read(Composite.java:1383)
    at org.simpleframework.xml.core.Composite.read(Composite.java:201)
    at org.simpleframework.xml.core.Composite.read(Composite.java:148)
    at org.simpleframework.xml.core.Composite.readVariable(Composite.java:623)
    at org.simpleframework.xml.core.Composite.readInstance(Composite.java:573)
    at org.simpleframework.xml.core.Composite.readUnion(Composite.java:549)
    at org.simpleframework.xml.core.Composite.readElement(Composite.java:532)
    at org.simpleframework.xml.core.Composite.readElements(Composite.java:445)
    at org.simpleframework.xml.core.Composite.access$400(Composite.java:59)
    at org.simpleframework.xml.core.Composite$Builder.read(Composite.java:1383)
    at org.simpleframework.xml.core.Composite.read(Composite.java:201)
    at org.simpleframework.xml.core.Composite.read(Composite.java:148)
    at org.simpleframework.xml.core.Composite.readVariable(Composite.java:623)
    at org.simpleframework.xml.core.Composite.readInstance(Composite.java:573)
    at org.simpleframework.xml.core.Composite.readUnion(Composite.java:549)
    at org.simpleframework.xml.core.Composite.readElement(Composite.java:532)
    at org.simpleframework.xml.core.Composite.readElements(Composite.java:445)
    at org.simpleframework.xml.core.Composite.access$400(Composite.java:59)
    at org.simpleframework.xml.core.Composite$Builder.read(Composite.java:1383)
    at org.simpleframework.xml.core.Composite.read(Composite.java:201)
    at org.simpleframework.xml.core.Composite.read(Composite.java:148)
    at org.simpleframework.xml.core.Traverser.read(Traverser.java:92)
    at org.simpleframework.xml.core.Persister.read(Persister.java:625)
    at org.simpleframework.xml.core.Persister.read(Persister.java:606)
    at org.simpleframework.xml.core.Persister.read(Persister.java:584)
    at org.simpleframework.xml.core.Persister.read(Persister.java:543)
    at org.simpleframework.xml.core.Persister.read(Persister.java:444)
    at org.linguafranca.pwdb.kdbx.simple.SimpleSerializableDatabase.load(SimpleSerializableDatabase.java:75)
    ... 5 more

Opening with JacksonDatabase:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Item" (class org.linguafranca.pwdb.kdbx.jackson.model.KeePassFile$CustomData), not marked as ignorable (one known property: "any"])
 at [Source: (GZIPInputStream); line: 36, column: 10] (through reference chain: org.linguafranca.pwdb.kdbx.jackson.model.KeePassFile["Meta"]->org.linguafranca.pwdb.kdbx.jackson.model.KeePassFile$Meta["CustomData"]->org.linguafranca.pwdb.kdbx.jackson.model.KeePassFile$CustomData["Item"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:1153)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:2241)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1793)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1771)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:316)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:310)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:310)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
    at com.fasterxml.jackson.dataformat.xml.deser.XmlDeserializationContext.readRootValue(XmlDeserializationContext.java:104)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4905)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3885)
    at org.linguafranca.pwdb.kdbx.jackson.JacksonSerializableDatabase.load(JacksonSerializableDatabase.java:72)
    at org.linguafranca.pwdb.kdbx.jackson.JacksonSerializableDatabase.load(JacksonSerializableDatabase.java:45)
    at org.linguafranca.pwdb.kdbx.KdbxStreamFormat.load(KdbxStreamFormat.java:65)
    at org.linguafranca.pwdb.kdbx.jackson.JacksonDatabase.load(JacksonDatabase.java:81)
    at FOO.keepass2helm.Example.main(Example.kt:21)
    at FOO.keepass2helm.ExampleKt.main(Example.kt:77)
    Suppressed: com.fasterxml.jackson.core.JsonParseException: pad block corrupted
 at [Source: (GZIPInputStream); line: 36, column: 10]
        at com.fasterxml.jackson.dataformat.xml.util.StaxUtil.throwAsParseException(StaxUtil.java:25)
        at com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser.close(FromXmlParser.java:538)
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4913)
        ... 7 more
    Caused by: org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
        at org.bouncycastle.crypto.paddings.PKCS7Padding.padCount(Unknown Source)
        at org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher.doFinal(Unknown Source)
        at org.bouncycastle.crypto.io.CipherInputStream.finaliseCipher(Unknown Source)
        at org.bouncycastle.crypto.io.CipherInputStream.close(Unknown Source)
        at java.base/java.util.zip.InflaterInputStream.close(InflaterInputStream.java:231)
        at java.base/java.util.zip.GZIPInputStream.close(GZIPInputStream.java:136)
        at com.fasterxml.aalto.in.StreamScanner._closeSource(StreamScanner.java:117)
        at com.fasterxml.aalto.in.XmlScanner.close(XmlScanner.java:351)
        at com.fasterxml.aalto.stax.StreamReaderImpl._closeScanner(StreamReaderImpl.java:1854)
        at com.fasterxml.aalto.stax.StreamReaderImpl.closeCompletely(StreamReaderImpl.java:1553)
        at com.fasterxml.jackson.dataformat.xml.deser.XmlTokenStream.closeCompletely(XmlTokenStream.java:351)
        at com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser.close(FromXmlParser.java:533)
        ... 8 more

Jax and Dom work without the issue.

If I export the file as YAML and check the Object, i see there are 3:

        <CustomData>
            <Item>
                <Key>KPXC_autosaveDelayMin</Key>
                <Value>0</Value>
            </Item>
            <Item>
                <Key>KPXC_RANDOM_SLUG</Key>
                <Value>XXXXXXXXXXXXXXX</Value>
            </Item>
            <Item>
                <Key>_LAST_MODIFIED</Key>
                <Value>Wed Nov X XX:XX:XX 2024 GMT</Value>
            </Item>
        </CustomData>

This is probably something that came in with manipulating the DB with KeePassXC from here and here.

haroon-sheikh commented 1 day ago

We're seeing the same issue on our side when using the JacksonDatabase.

jorabin-sense commented 1 day ago

Hey @lordgreg

Could you please confirm that you are using version 2.2.2?

I suspect the reason for this is that CustomData has been defined as being empty in both Simple and Jackson (which copied Simple to some degree) - whereas DOM and JAXB don't care about elements they don't know about. It's interesting that this has not come up before.

Could you please supply some kind of test file containing "safe" data so I can include it in a test for the fix.

A fix will be made in 2.2.3.

NB 2.2.3 provides in-memory protection of Strings for Jackson only and is from now on the very much the preferred implementation. The others will be dropped in V3. See https://github.com/jorabin/KeePassJava2/discussions/60 and https://github.com/jorabin/KeePassJava2/discussions/62.

Thanks Jo

jorabin-sense commented 1 day ago

Hi @haroon-sheikh

Likewise to the above - would you please supply a safe test file ...

Thanks Jo

lordgreg commented 1 day ago

Hi @jorabin-sense ,

Yes, I am using the version 2.2.2: image

test-KeePassJava2.kdbx.zip Pass: KeePassJava2

File doesnt have entries, but does have the Fields:

        <CustomData>
            <Item>
                <Key>KPXC_RANDOM_SLUG</Key>
                <Value>df59b2ef51126309416ff8b48ea69dfaa9f00c8699e4d0201da51aecf663d2edb697e5d733cf8fca2613c4d697f735181ca72e6ddd4f676e0e73cef9e655ac95abbcec5b9a7fc119e2932e56cc65c8b189af96861c2362f5abbec173dc8a11e0d02bdc7346361943ec6f88a5071ed197af851de0f52c7d9bf6ac1fc8952a85973a05f59a77765348db6c7ee97c1ecba2b22fb269c9d3bb978ef492994abfee6be48a0f963e82a9073d20392bbe2181da18bdb08e49fd8d194a77f96dbadfa185dc47f0084270a3995bc7c17112a02e58fa9493236eacf40f72e274e73f0189887c9707f26caeff9dccd83530a2f95e118b209cbd4c5b04cee48b329954</Value>
            </Item>
            <Item>
                <Key>_LAST_MODIFIED</Key>
                <Value>Wed Nov 6 13:53:33 2024 GMT</Value>
            </Item>
            <Item>
                <Key>KPXC_DECRYPTION_TIME_PREFERENCE</Key>
                <Value>1000</Value>
            </Item>
        </CustomData>

This is easily reproducible if you just create a new KDBX in KeePassXC :).

haroon-sheikh commented 1 day ago

Thanks for looking into this @jorabin-sense, I can confirm, we're also using 2.2.2.

test.kdbx.zip Pass: KeePassJava2