Retrieve storage password from keyring?

There are plenty of posts about restoring lost passwords-- most of it centers around launching the web ui with -print-credentials, but that didn’t work for me*.

It’s been mentioned that you can recover the password from the duplicacy.json file. Is that equivalent to the keyring in the CLI version? If so, how can I recover from that?

*to clarify not working for me: yes, I installed DebugView, but the password was not output there. Maybe it’s looking for the config file in the wrong place? In any case, if there’s a separate way to restore from the json file, I’d prefer that.

What did not work? Did you run the backup or check after launching the app?

I don’t know what DebugView is.

  1. Open terminal
  2. Run the web ui with that command line argument
  3. Start backup.
  4. Watch the credentials printed in the terminal.

Alternatively you can use tools like Process Explorer and inspect environment variables of the duplicacy CLI that web ui launched. Storage credentials are passed through the environment variables.

It looks like I confused some concepts before, let me back up (heh).

  1. I’m using the CLI version. When I said duplicacy.json file, I was looking at the .duplicacy/keyring file instead.
  2. I’m only just using the web interface for the first time now, is there a way to import my CLI settings?
  3. DebugView is a program for windows that is necessary to see the credentials printed on windows, or at least was back when I found that post.
1 Like
  1. Ok, that changes things quite a bit.
  2. Nope.
  3. Got it.

Keyring file on windows contains data encrypted with current user credentials.

I asked LLM to write you a script to decode it. I have no idea if this will work at all. I don’t have windows to try. But anyway, maybe worth a shot.

code

# Decrypt all entries from Duplicacy keyring on Windows
# Must be run as the same Windows user that created the keyring

$keyringPath = "$env:USERPROFILE\.duplicacy\keyring"

if (-not (Test-Path $keyringPath)) {
    Write-Error "Duplicacy keyring not found at $keyringPath"
    exit 1
}

Write-Host "Reading keyring from $keyringPath`n"

Get-Content $keyringPath | ForEach-Object {
    if ($_ -match "=") {
        $parts = $_ -split "=",2
        $name = $parts[0].Trim()
        $base64 = $parts[1].Trim()

        try {
            $bytes = [System.Convert]::FromBase64String($base64)
            $decrypted = [System.Security.Cryptography.ProtectedData]::Unprotect(
                $bytes,
                $null,
                [System.Security.Cryptography.DataProtectionScope]::CurrentUser
            )
            $secret = [System.Text.Encoding]::UTF8.GetString($decrypted)
            Write-Host "$name = $secret"
        }
        catch {
            Write-Warning "Failed to decrypt entry: $name"
        }
    }
}

Usage
1. Save this as dump-duplicacy-keyring.ps1.
2. Open PowerShell as the same user who runs Duplicacy.
3. Run:

    .\dump-duplicacy-keyring.ps1

Excellent, thank you!

I copied some parts of the script to do things manually, I’ll come back and fix up the whole script so it works for others without modification.

One last question: do you know what the “password” field is in the keyring? I understand the b2_id, b2_key, STORAGENAME_password and STORAGENAME_ssh_password fields, but I don’t know what password on its own corresponds to.

Probably storage encryption password?

Then what is STORAGENAME_password?

One is storage-specific, one is for default storage? Try both

Here’s the fixed version of the script:

<#
.DESCRIPTION
Decrypt all entries from Duplicacy keyring on Windows.

Must be run as the same Windows user that created the keyring.
#>

param (
    [Parameter(Position = 0, ParameterSetName = "path")]
    [string]$keyringPath = "$env:USERPROFILE\.duplicacy\keyring",

    [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = "object")]
    [hashtable]$hashTable
)


if ($PSCmdlet.ParameterSetName -eq "path") {
    Write-Verbose "Reading keyring from $keyringPath`n"
    $stringData = Get-Content $keyringPath
    $hashTable = $stringData | ConvertFrom-Json -AsHashtable
}

function Convert-And-Decrypt([string]$base64String) {
    $bytes = [System.Convert]::FromBase64String($base64String)
    $decrypted = [System.Security.Cryptography.ProtectedData]::Unprotect(
        $bytes,
        $null,
        [System.Security.Cryptography.DataProtectionScope]::CurrentUser
    )
    return [System.Text.Encoding]::UTF8.GetString($decrypted)
}

$convertedHashTable = $hashTable.Clone()

foreach ($key in $hashTable.Keys) {
    $convertedHashTable[$key] = Convert-And-Decrypt $hashTable[$key]
}

$convertedHashTable

And yes, it looks like password was for the default storage (b2), while STORAGE_password was for my sftp storage. Thank you!

1 Like