mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Parse new TOTP fields from KeePass 2.47 #850
This commit is contained in:
@@ -57,13 +57,25 @@ object OtpEntryFields {
|
|||||||
private const val DIGITS_KEY = "size"
|
private const val DIGITS_KEY = "size"
|
||||||
private const val STEP_KEY = "step"
|
private const val STEP_KEY = "step"
|
||||||
|
|
||||||
// HmacOtp KeePass2 values (https://keepass.info/help/base/placeholders.html#hmacotp)
|
// HmacOtp KeePass2 values (https://keepass.info/help/base/placeholders.html#otp)
|
||||||
private const val HMACOTP_SECRET_FIELD = "HmacOtp-Secret"
|
private const val HMACOTP_SECRET_FIELD = "HmacOtp-Secret"
|
||||||
private const val HMACOTP_SECRET_HEX_FIELD = "HmacOtp-Secret-Hex"
|
private const val HMACOTP_SECRET_HEX_FIELD = "HmacOtp-Secret-Hex"
|
||||||
private const val HMACOTP_SECRET_BASE32_FIELD = "HmacOtp-Secret-Base32"
|
private const val HMACOTP_SECRET_BASE32_FIELD = "HmacOtp-Secret-Base32"
|
||||||
private const val HMACOTP_SECRET_BASE64_FIELD = "HmacOtp-Secret-Base64"
|
private const val HMACOTP_SECRET_BASE64_FIELD = "HmacOtp-Secret-Base64"
|
||||||
private const val HMACOTP_SECRET_COUNTER_FIELD = "HmacOtp-Counter"
|
private const val HMACOTP_SECRET_COUNTER_FIELD = "HmacOtp-Counter"
|
||||||
|
|
||||||
|
// TimeOtp KeePass2 values
|
||||||
|
private const val TIMEOTP_SECRET_FIELD = "TimeOtp-Secret"
|
||||||
|
private const val TIMEOTP_SECRET_HEX_FIELD = "TimeOtp-Secret-Hex"
|
||||||
|
private const val TIMEOTP_SECRET_BASE32_FIELD = "TimeOtp-Secret-Base32"
|
||||||
|
private const val TIMEOTP_SECRET_BASE64_FIELD = "TimeOtp-Secret-Base64"
|
||||||
|
private const val TIMEOTP_LENGTH_FIELD = "TimeOtp-Length"
|
||||||
|
private const val TIMEOTP_PERIOD_FIELD = "TimeOtp-Period"
|
||||||
|
private const val TIMEOTP_ALGORITHM_FIELD = "TimeOtp-Algorithm"
|
||||||
|
private const val TIMEOTP_ALGORITHM_SHA1_VALUE = "HMAC-SHA-1"
|
||||||
|
private const val TIMEOTP_ALGORITHM_SHA256_VALUE = "HMAC-SHA-256"
|
||||||
|
private const val TIMEOTP_ALGORITHM_SHA512_VALUE = "HMAC-SHA-512"
|
||||||
|
|
||||||
// Custom fields (maybe from plugin)
|
// Custom fields (maybe from plugin)
|
||||||
private const val TOTP_SEED_FIELD = "TOTP Seed"
|
private const val TOTP_SEED_FIELD = "TOTP Seed"
|
||||||
private const val TOTP_SETTING_FIELD = "TOTP Settings"
|
private const val TOTP_SETTING_FIELD = "TOTP Settings"
|
||||||
@@ -85,14 +97,17 @@ object OtpEntryFields {
|
|||||||
// OTP (HOTP/TOTP) from URL and field from KeePassXC
|
// OTP (HOTP/TOTP) from URL and field from KeePassXC
|
||||||
if (parseOTPUri(getField, otpElement))
|
if (parseOTPUri(getField, otpElement))
|
||||||
return otpElement
|
return otpElement
|
||||||
|
// TOTP from KeePass 2.47
|
||||||
|
if (parseTOTPFromOfficialField(getField, otpElement))
|
||||||
|
return otpElement
|
||||||
// TOTP from key values (maybe plugin or old KeePassXC)
|
// TOTP from key values (maybe plugin or old KeePassXC)
|
||||||
if (parseTOTPKeyValues(getField, otpElement))
|
if (parseTOTPKeyValues(getField, otpElement))
|
||||||
return otpElement
|
return otpElement
|
||||||
// TOTP from custom field
|
// TOTP from custom field
|
||||||
if (parseTOTPFromField(getField, otpElement))
|
if (parseTOTPFromPluginField(getField, otpElement))
|
||||||
return otpElement
|
return otpElement
|
||||||
// HOTP fields from KeePass 2
|
// HOTP fields from KeePass 2
|
||||||
if (parseHOTPFromField(getField, otpElement))
|
if (parseHOTPFromOfficialField(getField, otpElement))
|
||||||
return otpElement
|
return otpElement
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -266,6 +281,39 @@ object OtpEntryFields {
|
|||||||
return Uri.encode(parameter.removeLineChars())
|
return Uri.encode(parameter.removeLineChars())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseTOTPFromOfficialField(getField: (id: String) -> String?, otpElement: OtpElement): Boolean {
|
||||||
|
val secretField = getField(TIMEOTP_SECRET_FIELD)
|
||||||
|
val secretHexField = getField(TIMEOTP_SECRET_HEX_FIELD)
|
||||||
|
val secretBase32Field = getField(TIMEOTP_SECRET_BASE32_FIELD)
|
||||||
|
val secretBase64Field = getField(TIMEOTP_SECRET_BASE64_FIELD)
|
||||||
|
val lengthField = getField(TIMEOTP_LENGTH_FIELD)
|
||||||
|
val periodField = getField(TIMEOTP_PERIOD_FIELD)
|
||||||
|
val algorithmField = getField(TIMEOTP_ALGORITHM_FIELD)
|
||||||
|
try {
|
||||||
|
when {
|
||||||
|
secretField != null -> otpElement.setUTF8Secret(secretField)
|
||||||
|
secretHexField != null -> otpElement.setHexSecret(secretHexField)
|
||||||
|
secretBase32Field != null -> otpElement.setBase32Secret(secretBase32Field)
|
||||||
|
secretBase64Field != null -> otpElement.setBase64Secret(secretBase64Field)
|
||||||
|
lengthField != null -> otpElement.digits = lengthField.toIntOrNull() ?: OTP_DEFAULT_DIGITS
|
||||||
|
periodField != null -> otpElement.period = periodField.toIntOrNull() ?: TOTP_DEFAULT_PERIOD
|
||||||
|
algorithmField != null -> otpElement.algorithm =
|
||||||
|
when (algorithmField.toUpperCase(Locale.ENGLISH)) {
|
||||||
|
TIMEOTP_ALGORITHM_SHA1_VALUE -> HashAlgorithm.SHA1
|
||||||
|
TIMEOTP_ALGORITHM_SHA256_VALUE -> HashAlgorithm.SHA256
|
||||||
|
TIMEOTP_ALGORITHM_SHA512_VALUE -> HashAlgorithm.SHA512
|
||||||
|
else -> HashAlgorithm.SHA1
|
||||||
|
}
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
otpElement.type = OtpType.TOTP
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseTOTPKeyValues(getField: (id: String) -> String?, otpElement: OtpElement): Boolean {
|
private fun parseTOTPKeyValues(getField: (id: String) -> String?, otpElement: OtpElement): Boolean {
|
||||||
val plainText = getField(OTP_FIELD)
|
val plainText = getField(OTP_FIELD)
|
||||||
if (plainText != null && plainText.isNotEmpty()) {
|
if (plainText != null && plainText.isNotEmpty()) {
|
||||||
@@ -291,7 +339,7 @@ object OtpEntryFields {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseTOTPFromField(getField: (id: String) -> String?, otpElement: OtpElement): Boolean {
|
private fun parseTOTPFromPluginField(getField: (id: String) -> String?, otpElement: OtpElement): Boolean {
|
||||||
val seedField = getField(TOTP_SEED_FIELD) ?: return false
|
val seedField = getField(TOTP_SEED_FIELD) ?: return false
|
||||||
try {
|
try {
|
||||||
otpElement.setBase32Secret(seedField)
|
otpElement.setBase32Secret(seedField)
|
||||||
@@ -317,7 +365,7 @@ object OtpEntryFields {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseHOTPFromField(getField: (id: String) -> String?, otpElement: OtpElement): Boolean {
|
private fun parseHOTPFromOfficialField(getField: (id: String) -> String?, otpElement: OtpElement): Boolean {
|
||||||
val secretField = getField(HMACOTP_SECRET_FIELD)
|
val secretField = getField(HMACOTP_SECRET_FIELD)
|
||||||
val secretHexField = getField(HMACOTP_SECRET_HEX_FIELD)
|
val secretHexField = getField(HMACOTP_SECRET_HEX_FIELD)
|
||||||
val secretBase32Field = getField(HMACOTP_SECRET_BASE32_FIELD)
|
val secretBase32Field = getField(HMACOTP_SECRET_BASE32_FIELD)
|
||||||
@@ -383,25 +431,43 @@ object OtpEntryFields {
|
|||||||
val totpSeedField = Field(TOTP_SEED_FIELD)
|
val totpSeedField = Field(TOTP_SEED_FIELD)
|
||||||
val totpSettingField = Field(TOTP_SETTING_FIELD)
|
val totpSettingField = Field(TOTP_SETTING_FIELD)
|
||||||
val hmacOtpSecretField = Field(HMACOTP_SECRET_FIELD)
|
val hmacOtpSecretField = Field(HMACOTP_SECRET_FIELD)
|
||||||
val hmacOtpSecretHewField = Field(HMACOTP_SECRET_HEX_FIELD)
|
val hmacOtpSecretHexField = Field(HMACOTP_SECRET_HEX_FIELD)
|
||||||
val hmacOtpSecretBase32Field = Field(HMACOTP_SECRET_BASE32_FIELD)
|
val hmacOtpSecretBase32Field = Field(HMACOTP_SECRET_BASE32_FIELD)
|
||||||
val hmacOtpSecretBase64Field = Field(HMACOTP_SECRET_BASE64_FIELD)
|
val hmacOtpSecretBase64Field = Field(HMACOTP_SECRET_BASE64_FIELD)
|
||||||
val hmacOtpSecretCounterField = Field(HMACOTP_SECRET_COUNTER_FIELD)
|
val hmacOtpSecretCounterField = Field(HMACOTP_SECRET_COUNTER_FIELD)
|
||||||
|
val timeOtpSecretField = Field(TIMEOTP_SECRET_FIELD)
|
||||||
|
val timeOtpSecretHexField = Field(TIMEOTP_SECRET_HEX_FIELD)
|
||||||
|
val timeOtpSecretBase32Field = Field(TIMEOTP_SECRET_BASE32_FIELD)
|
||||||
|
val timeOtpSecretBase64Field = Field(TIMEOTP_SECRET_BASE64_FIELD)
|
||||||
|
val timeOtpLengthField = Field(TIMEOTP_LENGTH_FIELD)
|
||||||
|
val timeOtpPeriodField = Field(TIMEOTP_PERIOD_FIELD)
|
||||||
|
val timeOtpAlgorithmField = Field(TIMEOTP_ALGORITHM_FIELD)
|
||||||
newCustomFields.remove(otpField)
|
newCustomFields.remove(otpField)
|
||||||
newCustomFields.remove(totpSeedField)
|
newCustomFields.remove(totpSeedField)
|
||||||
newCustomFields.remove(totpSettingField)
|
newCustomFields.remove(totpSettingField)
|
||||||
newCustomFields.remove(hmacOtpSecretField)
|
newCustomFields.remove(hmacOtpSecretField)
|
||||||
newCustomFields.remove(hmacOtpSecretHewField)
|
newCustomFields.remove(hmacOtpSecretHexField)
|
||||||
newCustomFields.remove(hmacOtpSecretBase32Field)
|
newCustomFields.remove(hmacOtpSecretBase32Field)
|
||||||
newCustomFields.remove(hmacOtpSecretBase64Field)
|
newCustomFields.remove(hmacOtpSecretBase64Field)
|
||||||
newCustomFields.remove(hmacOtpSecretCounterField)
|
newCustomFields.remove(hmacOtpSecretCounterField)
|
||||||
|
newCustomFields.remove(timeOtpSecretField)
|
||||||
|
newCustomFields.remove(timeOtpSecretHexField)
|
||||||
|
newCustomFields.remove(timeOtpSecretBase32Field)
|
||||||
|
newCustomFields.remove(timeOtpSecretBase64Field)
|
||||||
|
newCustomFields.remove(timeOtpLengthField)
|
||||||
|
newCustomFields.remove(timeOtpPeriodField)
|
||||||
|
newCustomFields.remove(timeOtpAlgorithmField)
|
||||||
// Empty auto generated OTP Token field
|
// Empty auto generated OTP Token field
|
||||||
if (fieldsToParse.contains(otpField)
|
if (fieldsToParse.contains(otpField)
|
||||||
|| fieldsToParse.contains(totpSeedField)
|
|| fieldsToParse.contains(totpSeedField)
|
||||||
|| fieldsToParse.contains(hmacOtpSecretField)
|
|| fieldsToParse.contains(hmacOtpSecretField)
|
||||||
|| fieldsToParse.contains(hmacOtpSecretHewField)
|
|| fieldsToParse.contains(hmacOtpSecretHexField)
|
||||||
|| fieldsToParse.contains(hmacOtpSecretBase32Field)
|
|| fieldsToParse.contains(hmacOtpSecretBase32Field)
|
||||||
|| fieldsToParse.contains(hmacOtpSecretBase64Field)
|
|| fieldsToParse.contains(hmacOtpSecretBase64Field)
|
||||||
|
|| fieldsToParse.contains(timeOtpSecretField)
|
||||||
|
|| fieldsToParse.contains(timeOtpSecretHexField)
|
||||||
|
|| fieldsToParse.contains(timeOtpSecretBase32Field)
|
||||||
|
|| fieldsToParse.contains(timeOtpSecretBase64Field)
|
||||||
)
|
)
|
||||||
newCustomFields.add(Field(OTP_TOKEN_FIELD))
|
newCustomFields.add(Field(OTP_TOKEN_FIELD))
|
||||||
return newCustomFields
|
return newCustomFields
|
||||||
|
|||||||
Reference in New Issue
Block a user