138 Commits

Author SHA1 Message Date
d249b9241e Delete 'lib/Bitwarden CLI/bw_macOS' 2022-12-30 13:29:30 -05:00
fc80eaab16 Delete 'lib/Bitwarden CLI/bw_linux' 2022-12-30 13:29:23 -05:00
9f73fee228 Delete 'lib/Bitwarden CLI/bw.exe' 2022-12-30 13:29:17 -05:00
crp3844
4118a8d077 updated BW CLI to 2022.11.0 2022-12-14 10:12:45 -05:00
72df3e504a removed does_file_exists function. added a removal of bad export file and sleep time. Still getting empty export files, no idea why 2022-10-07 21:29:06 -04:00
04ad1dbba6 added no encryption option. Also added for loops for csv and json exports as some are failing 2022-10-07 21:00:05 -04:00
1e4ed58fe6 changed to get some error codes when things don't work 2022-09-14 19:30:24 -04:00
75562c141f moved logger options after log_file variable 2022-09-14 18:38:09 -04:00
f9bef2bce2 added sdelete path variable, added logic for secure delete, removed import and secure_delete commands 2022-09-14 18:35:02 -04:00
8938c0378a removed MacOS from supported OSes and added gpg linux exe 2022-09-14 18:15:38 -04:00
0023557177 moved variables and OS login into main program 2022-09-14 18:14:40 -04:00
3baac3958b changed from stderr to stdout 2022-09-13 23:31:11 -04:00
c00c7ba4ec removed old comments 2022-09-13 23:30:03 -04:00
9359b36c6f added windows gpg exe path, added gpg command 2022-09-13 23:29:43 -04:00
5ed4f3da76 added zipping of files and commented out removal of zip for testing 2022-09-13 22:36:53 -04:00
7ec0116fa5 added shutil and removal of working dir after secure delete 2022-09-13 22:29:20 -04:00
8f8746e4fa updated secure delete for working directory 2022-09-13 22:27:02 -04:00
ad035cae11 updated exports to use working folder 2022-09-13 22:26:33 -04:00
1284693cf7 added exports and working directory variables 2022-09-13 22:25:30 -04:00
70c07fb605 added working and export directory 2022-09-13 22:25:02 -04:00
af3128c7f7 Merge branch 'master' of https://git.johnhgaunt.com/jgaunt/bitwardenbackup 2022-09-09 23:53:42 -04:00
d52abb2a4d trying out secure delete but *.cvs doesn't work. 2022-09-09 23:53:35 -04:00
946d627482 added pip requirements.txt file for packages needed 2022-09-09 13:43:32 -04:00
183aadf796 remove printing of item 2022-09-08 20:52:13 -04:00
305d7f9019 fixed attachment download loop 2022-09-08 20:50:08 -04:00
4ac0a2db37 remove unneeded array and added time for sleep between attachment downloads 2022-09-08 20:17:31 -04:00
b1077dc4be added attachment loop search and save 2022-09-08 20:15:21 -04:00
c2e3c37e24 updated export file names to include email and date and organization name fo those 2022-09-08 19:04:46 -04:00
859ccb675f added datetime for export file names 2022-09-08 19:01:38 -04:00
e6dbe90d81 removed print of organization array and added loop for exporting organization vault 2022-09-08 18:51:16 -04:00
crp3844
70a4bb41a0 updated parser descriptions 2022-09-08 15:45:52 -04:00
crp3844
6cab1b4573 added message to create accounts if none exist 2022-09-08 15:43:20 -04:00
crp3844
9e43bc7126 removal of accounts and emails variable at end of script 2022-09-08 15:40:46 -04:00
crp3844
58a7b002ba removal of vault password at end of loop 2022-09-08 15:40:15 -04:00
crp3844
79d56d00d0 added number of organizations and fixed command for getting them 2022-09-08 14:11:53 -04:00
crp3844
c0890fd57d updated unsupported OS message 2022-09-08 13:14:36 -04:00
crp3844
88268d4889 removed utils as we built our own 2022-09-08 13:13:40 -04:00
crp3844
303e11b348 remove configparser 2022-09-08 13:12:44 -04:00
crp3844
add98a058f removed lib from gitignore and file changes coming in now 2022-09-08 09:33:54 -04:00
crp3844
824eb2488d moved the libs into some folders, added bw cli macos and supported os logic. updated code to use new paths 2022-09-08 09:31:17 -04:00
crp3844
fddaf8ac15 added organization code and removed from periods from logs 2022-09-08 09:27:50 -04:00
crp3844
7be43da4c0 removed the FreeBSD test case support 2022-09-08 09:22:36 -04:00
5032946e14 moved export commands to only run when unlocked vault. updated unset session variable only if it is set 2022-09-07 22:00:03 -04:00
a5ca8d2207 update some of the logging commands and fixed logging to logger 2022-09-07 21:43:39 -04:00
641ffacfb4 added bitwarden code to login, unlock, and export vault 2022-09-07 21:32:46 -04:00
addf7f27c4 added .config files to ignore 2022-09-07 19:50:48 -04:00
5f95747b05 remove printing accounts 2022-09-07 19:50:07 -04:00
afdbaa0ae7 removed ini file 2022-09-07 19:49:38 -04:00
crp3844
07a38c93e6 forgot a few more client options 2022-09-07 15:33:21 -04:00
crp3844
5ec6f2b415 forgot one client to remove 2022-09-07 15:28:44 -04:00
crp3844
60e19cc718 removed client from options for functions as it is a global variable 2022-09-07 15:27:46 -04:00
crp3844
ed5ba18ca7 updated function name 2022-09-07 15:25:52 -04:00
crp3844
892e8548b9 removed old non used code 2022-09-07 15:25:00 -04:00
crp3844
e249901af1 removed extra arguments and encrypt/decrypt section 2022-09-07 15:23:58 -04:00
crp3844
d410ff8aad removal print of secrets file path 2022-09-07 15:17:02 -04:00
crp3844
d11baaff9c updated config while loop to work when secrets files is removed 2022-09-07 15:16:14 -04:00
crp3844
de32b4c6e6 added removal of secrets config file if last account is removed 2022-09-07 15:11:25 -04:00
crp3844
7c37b9bb3e added some spacing on the select account to edit/delete 2022-09-07 15:06:33 -04:00
crp3844
3d60dcdcb2 moved confirmation question into the while loop 2022-09-07 15:05:00 -04:00
crp3844
b2a8ea6f71 updated some logging, added ask for confirmation function, added edit account function 2022-09-07 15:03:12 -04:00
crp3844
248aa408ba updated selecting account and delete account 2022-09-07 13:44:56 -04:00
crp3844
acbcfa1c1d fixed adding dict to dict 2022-09-07 11:42:25 -04:00
crp3844
d25282a6fd updated new account function 2022-09-07 11:37:42 -04:00
crp3844
6ce71bbd61 changed from ini to whole file encryption 2022-09-07 11:33:37 -04:00
crp3844
a4bac299ac forgot to return the decrypted value with new function 2022-09-07 11:10:23 -04:00
crp3844
70aa686988 removed extra decrypt version finder 2022-09-07 11:07:36 -04:00
crp3844
f22321e226 update getpass calls 2022-09-07 11:05:54 -04:00
crp3844
75dfd0c758 added encrypt and decrypt testing 2022-09-07 11:04:47 -04:00
crp3844
dab4eaa585 added configparser back in to test with 2022-09-07 10:57:41 -04:00
crp3844
f9189ee111 added test decrypt parser 2022-09-07 10:49:14 -04:00
crp3844
8de62c4b5d forgot ini file 2022-09-07 10:43:05 -04:00
crp3844
a8cb3ca250 added read config file and testing results 2022-09-07 10:42:04 -04:00
crp3844
d684cd0360 switch from a match to if else 2022-09-07 10:32:25 -04:00
crp3844
503e5bce53 updated get account details to only return encryption. updated new account to use the encrypted fields 2022-09-07 10:29:45 -04:00
crp3844
e16cd74e4d added decryption version functions 2022-09-07 10:26:56 -04:00
crp3844
469c838447 stupid indents 2022-09-07 08:35:05 -04:00
crp3844
710359b324 keeping client open 2022-09-07 08:34:17 -04:00
crp3844
90268494a7 removed old variables 2022-09-07 08:32:42 -04:00
crp3844
142eb62ea4 updated parser and get account details testing of encrypted data 2022-09-07 08:29:43 -04:00
ae59d4975e updated logger for console and file 2022-09-06 22:36:35 -04:00
6ac6337b86 added log file path, adding logger function, updated logger levels 2022-09-06 22:29:39 -04:00
77d8d51540 added hmac library and removed config options from the client 2022-09-06 22:10:21 -04:00
3b51a9a065 added base64 library 2022-09-06 21:50:33 -04:00
71187689a9 added secrets import 2022-09-06 21:49:51 -04:00
8d77101cc2 added freebsd test cass. updated file paths to be os agnostic 2022-09-06 21:48:03 -04:00
9fa801908d added logging, parser, and test client 2022-09-06 20:56:01 -04:00
171d5617b2 added pykmip functions 2022-09-06 20:50:17 -04:00
5c7b348b1b added conf dir with client pykmip sample file 2022-09-06 20:41:47 -04:00
5958bfdd55 added while loop for top level config menu, updated delete question to standard we are using 2022-09-06 20:39:56 -04:00
7d9e4fa428 updated gitignore file 2022-09-06 20:38:47 -04:00
crp3844
ea90c0dc97 started work on configuration menu 2022-09-06 17:06:24 -04:00
crp3844
f823711817 lowercased variable names, added function to get account details and write basic config ini file 2022-09-06 15:46:51 -04:00
crp3844
247615d3d1 added sample ini file 2022-09-06 15:21:24 -04:00
crp3844
0cf3109b18 added getpass import 2022-09-06 14:56:41 -04:00
crp3844
de945f6668 added ini format, updated bw linux to correct file, added commnets for ini sections 2022-09-06 14:56:04 -04:00
crp3844
564e5f96bf reverted windows/linux test logic and added ini parser 2022-09-06 14:07:04 -04:00
crp3844
9add8abcbf added ini to ignore list 2022-09-06 14:06:31 -04:00
crp3844
fdc92823c7 Started python backup script 2022-09-06 14:03:26 -04:00
crp3844
a113fc49f5 added bw cli for linux 2022-09-06 14:02:53 -04:00
10da1b57e7 1.22.1 giving same error now, reverted to 2022.8.0 2022-09-05 15:36:48 -04:00
cefecdfd3b reverted to 1.22.1
Was getting this error:
pkg/prelude/bootstrap.js:1876
      throw error;
      ^

Error: EBADF: bad file descriptor, read
←[90m    at Object.readSync (node:fs:727:3)←[39m
    at Object.readSync (pkg/prelude/bootstrap.js:947:32)
    at readPayloadSync (pkg/prelude/bootstrap.js:461:13)
    at payloadCopyManySync (pkg/prelude/bootstrap.js:523:23)
    at payloadFileSync (pkg/prelude/bootstrap.js:559:3)
    at Object.internalModuleReadJSON (pkg/prelude/bootstrap.js:1834:10)
←[90m    at internalModuleReadJSON (node:internal/modules/package_json_reader:4:68)←[39m
←[90m    at Object.read (node:internal/modules/package_json_reader:21:42)←[39m
←[90m    at readPackage (node:internal/modules/cjs/loader:296:36)←[39m
←[90m    at resolveExports (node:internal/modules/cjs/loader:479:15)←[39m {
  errno: ←[33m-4083←[39m,
  syscall: ←[32m'read'←[39m,
  code: ←[32m'EBADF'←[39m
}
2022-09-05 15:05:07 -04:00
cfc821fa46 updated bw.exe to 2022.8.0 2022-09-04 23:29:36 -04:00
8beb0a56a9 updated to ignore gpg home 2022-08-07 16:18:10 -04:00
42ef3870d9 removed shorthand command aliases 2022-06-06 20:38:52 -04:00
662fc604cd updated gpg4win portable to 2.3.6 2022-06-06 20:33:55 -04:00
a793b91bb3 updated bw.exe to 1.22.1 2022-06-06 20:28:10 -04:00
8c2714a9d6 updated to work with api keys 2022-06-06 20:22:22 -04:00
e850610128 updated 7za to 21.07 2022-05-07 11:11:39 -04:00
5db8ed9259 removed all hashed code and self hosted url 2022-02-09 11:01:57 -05:00
baca57dd2b added quick notes for restoring attachments 2022-02-09 10:25:58 -05:00
5f3e7e0c1a Merge branch '2021Export' of https://git.johnhgaunt.com/jgaunt/bitwardenbackup 2022-01-03 09:28:56 -05:00
bd2cbc643e updated bw cli to 1.20.0 2021-12-20 16:44:29 -05:00
70920467e8 removed file hash check
it seems that during a git clone, all the file hashes are changed. removed the check until future notice.
Also removing signature file as that is having the same issue as the main script file hash changes and fails to verify
2021-11-26 12:35:12 -05:00
d406f89835 removed asc from ignore 2021-11-26 12:13:20 -05:00
2abcdbc50e updated sig to asc 2021-11-26 12:12:33 -05:00
8b7b83ee99 detached armor sig 2021-11-26 12:08:25 -05:00
fcac9fb9b7 Update bitwardenBackup.ps1.sig
so the gpg --sign was not detached which is what we want.
2021-11-26 12:06:04 -05:00
a409873f6b fixed the signature
the signature created with kleopatra would fail outside of the same computer.  Using the gpg --sign creates it correctly.
2021-11-26 12:00:35 -05:00
e2579b4057 problems with the signature on other computers
my win11 test computer didn't have any issues verify the sig but my laptop still does.
2021-11-26 11:55:55 -05:00
4af65b85e4 moved signature to armor 2021-11-26 11:54:02 -05:00
1bc05527d4 testing the signature 2021-11-26 11:24:25 -05:00
55b8e792ae new signature file 2021-11-25 12:49:56 -05:00
307eaa2a38 minor changes and comments 2021-11-25 12:48:57 -05:00
5c3b342c88 moved the $bw logout above the remove-variable so it works now. Created new signature 2021-11-25 12:01:43 -05:00
9e64f093ac added exit at the bottom and --no-options for gpg 2021-11-25 11:56:07 -05:00
86e16e64ee removed the gpg home from the ignore as the files are still hashed and causes errors 2021-11-25 11:52:20 -05:00
62a82ca818 updated gpg/home dir to ignore list 2021-11-25 11:26:06 -05:00
541ce541c9 created new signature 2021-11-25 11:15:51 -05:00
ee513a5e0e comment 2021-11-25 11:15:20 -05:00
c9546e3b91 updated hashes to use the compress to save a little bit of space 2021-11-25 11:14:59 -05:00
3649ca2167 added comments to generate file hashes 2021-11-25 11:12:15 -05:00
8481a48aa0 updated hashes file path to script path 2021-11-25 11:08:19 -05:00
1f97bbe182 added comments 2021-11-25 11:07:47 -05:00
fc2d98306a Update 'README.md' 2021-11-25 10:57:22 -05:00
ecccbc8226 added file hash check and sig to ensure the store file hashes can be checked 2021-11-25 10:51:11 -05:00
8cfb8f741b Merge branch 'master' of https://git.johnhgaunt.com/jgaunt/bitwardenbackup 2021-11-25 10:38:32 -05:00
1e6f5c37a8 removed adding path of lib folder and did absolute paths in the lib folder 2021-11-25 10:38:13 -05:00
02a247b61b Update 'README.md' 2021-11-24 13:40:29 -05:00
69 changed files with 997 additions and 76 deletions

133
.gitignore vendored
View File

@@ -1,9 +1,138 @@
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# config file
*config.yml
*config.py
*config.ini
*config.json
# config/secret/certs files
*.key
*.crt
*secrets.ini
*client.conf
*.config
# GPG files #
*.gpg
*.asc
*.pgp
*.age
*.csv
*.json
*.zip
attachments/
attachments/
lib/gpg/home/
working/
exports/

View File

@@ -10,4 +10,4 @@ Options:
-zip Zips the export/attachements into a zip
-encrypt Encrypts the zip file with gpg symmetric encryption using your vault password
-verbose Show verbose information
```
```

View File

@@ -6,93 +6,154 @@ param (
# Verbose output
if ($verbose) {
$oldverbose = $VerbosePreference
$VerbosePreference = "continue"
}
# get the date/time for the back filename
$dateTime = get-date -format ("yyyyMMdd-HHmmss")
$env:Path += ";$PSScriptRoot\lib;$PSScriptRoot\lib\gpg\bin;$PSScriptRoot\lib\age"
$dateTime = Get-Date -format ("yyyyMMdd-HHmmss")
# set the binaries path, do not rely on the path variables as they are not hashed
$bw = "$PSScriptRoot\lib\bw.exe"
$gpg = "$PSScriptRoot\lib\gpg\bin\gpg.exe"
$sdelete = "$PSScriptRoot\lib\sdelete.exe"
bw config server https://bitwarden.johnhgaunt.com
# set bitwarden server to my self hosted instance
#& $bw config server https://bitwarden.johnhgaunt.com
# begin while loop to login, if login is incorrect, ask user again
while ($true) {
$username = Read-Host "Please enter your bitwarden email"
$password = Read-Host -assecurestring "Please enter your bitwarden password"
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
$code = Read-Host "Please enter your 2fa code (hit enter if not used)"
if ($code -eq "") {
$sessionKey = $(bw login $username $password --raw --nointeraction)
} else {
$sessionKey = $(bw login $username $password --method 0 --code $code --raw --nointeraction)
}
$bwStatus = $(ConvertFrom-Json $(bw status))
if ($bwStatus.Status -ne "locked") {
# just writing a new line
Write-Host " "
Write-Warning "Unable to login, please try agian."
} else {
# ask for api client id/secret and password
$clientID = Read-Host "Please enter your Bitwarden API client_id"
$env:BW_CLIENTID = "$clientID"
$clientSecret = Read-Host -assecurestring "Please enter your bitwarden API client_secret"
$clientSecret = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($clientSecret))
$env:BW_CLIENTSECRET = "$clientSecret"
# test login
& $bw login --apikey --raw
$bwStatus = $(ConvertFrom-Json $(& $bw status))
if ($bwStatus."Status" -eq "locked") {
# Authentication was successful
# start new loop for password unlock
while ($true) {
$password = Read-Host -assecurestring "Please enter your Bitwarden password"
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
$sessionKey = $(& $bw unlock $password --raw --nointeraction)
# get the bw status to see if the login was successfull and inform user
$bwStatus = $(ConvertFrom-Json $(& $bw status --session $sessionKey))
if ($bwStatus."Status" -eq "unlocked") {
$username = $bwStatus."userEmail"
break
} else {
# just writing a new line
Write-Host " "
Write-Warning "Unable to unlock your vault, please try agian."
}
}
break
}
} else {
Write-Host " "
Write-Warning "Unable to authenticate, please try agian."
}
}
# Export the vault to both CSV and JSON files, this allows best compatibility to import again or switch managers.
Write-Host "Exporting vault to both CSV and JSON files."
Write-Verbose "Exporting vault to CSV."
bw export $password --output "$PSScriptRoot\Bitwarden User $username Export $dateTime.csv" --format csv --session $sessionKey
& $bw export $password --output "$PSScriptRoot\Bitwarden User $username Export $dateTime.csv" --format csv --session $sessionKey
# just writing a new line
Write-Host " "
Write-Verbose "Exporting vault to JSON."
bw export $password --output "$PSScriptRoot\Bitwarden User $username Export $dateTime.json" --format json --session $sessionKey
& $bw export $password --output "$PSScriptRoot\Bitwarden User $username Export $dateTime.json" --format json --session $sessionKey
# just writing a new line
Write-Host " "
# look for organizations
Write-Host "Looking for Organizations..."
$organizations = $(ConvertFrom-Json $(bw list organizations --session $sessionKey))
Write-Host "Found $(($organizations | measure).count) Organiztaions."
$organizations = $(ConvertFrom-Json $(& $bw list organizations --session $sessionKey))
Write-Host "Found $(($organizations | Measure-Object).count) Organiztaions."
$organizations | foreach {
# loop through the found organizations and again export both as CSV and JSON for best compatibility
$organizations | ForEach-Object {
Write-Host "Exporting organization $($_.name) vault to both CSV and JSON files."
Write-Verbose "Exporting organization vault to CSV."
bw export $password --organizationid $_.id --output "$PSScriptRoot\Bitwarden Organization $($_.name) Export $dateTime.csv" --format csv --session $sessionKey
& $bw export $password --organizationid $_.id --output "$PSScriptRoot\Bitwarden Organization $($_.name) Export $dateTime.csv" --format csv --session $sessionKey
# just writing a new line
Write-Host " "
Write-Verbose "Exporting organization vault to JSON."
bw export $password --organizationid $_.id --output "$PSScriptRoot\Bitwarden Organization $($_.name) Export $dateTime.json" --format json --session $sessionKey
& $bw export $password --organizationid $_.id --output "$PSScriptRoot\Bitwarden Organization $($_.name) Export $dateTime.json" --format json --session $sessionKey
# just writing a new line
Write-Host " "
}
# find all items with attachments
Write-Host "Looking for items with attachments..."
$itemsWithAttachments = $((ConvertFrom-Json $(bw list items --session $sessionKey)) | Where-Object attachments)
Write-Host "Found $(($itemsWithAttachments | measure).count) items with attachments."
$itemsWithAttachments = $((ConvertFrom-Json $(& $bw list items --session $sessionKey)) | Where-Object attachments)
Write-Host "Found $(($itemsWithAttachments | Measure-Object).count) items with attachments."
# loop through all the items with attachments and download them into a folder with the name of the item
Write-Host "Downloading attachments..."
$itemsWithAttachments | foreach {
$itemsWithAttachments | ForEach-Object {
Write-Verbose "Working on item $($_.name) ($($_.id))."
$folder="$PSScriptRoot\attachments\$($_.name)"
$itemID=$_.id
$_.attachments | foreach {
$_.attachments | ForEach-Object {
Write-Verbose "Downloading attachment ($($_.id)) with name $($_.fileName) to $folder."
bw get attachment $_.id --itemid $itemID --output "$folder\$($_.fileName)" --session $sessionKey
& $bw get attachment $_.id --itemid $itemID --output "$folder\$($_.fileName)" --session $sessionKey
# just writing a new line
Write-Host " "
sleep -Milliseconds 500
Start-Sleep -Milliseconds 500
}
}
# zip file name used below
$zipFilename = "Bitwarden Backup $dateTime.zip"
# if the user wants the export zipped or encrypted
if ($zip -or $encrypt) {
# zip the export
Write-Host "Zipping the backup together..."
Compress-Archive -Path $PSScriptRoot\*.csv, $PSScriptRoot\*.json, $PSScriptRoot\attachments -DestinationPath "$PSScriptRoot\$zipFilename"
# securely delete the export items with sdelete
Write-Host "Securely deleting the exports and attachments..."
sdelete64.exe -s -p 25 $PSScriptRoot\*.csv $PSScriptRoot\*.json $PSScriptRoot\attachments
& $sdelete -s -p 25 $PSScriptRoot\*.csv $PSScriptRoot\*.json $PSScriptRoot\attachments
# if encrypting the export
if ($encrypt) {
# encrypt the zip export with gpg
Write-Host "Encrypting the backup zip with your bitwarden password..."
gpg.exe --batch --passphrase "$password" --symmetric --cipher-algo AES256 --digest-algo SHA512 --compression-algo Uncompressed --output "$PSScriptRoot\$zipFilename.gpg" "$PSScriptRoot\$zipFilename"
& $gpg --no-options --batch --passphrase "$password" --symmetric --cipher-algo AES256 --digest-algo SHA512 --compression-algo Uncompressed --output "$PSScriptRoot\$zipFilename.gpg" "$PSScriptRoot\$zipFilename"
# securely delete the zip export with sdelete
Write-Host "Securely deleting the zip file..."
sdelete64.exe -p 25 "$PSScriptRoot\$zipFilename"
& $sdelete -p 25 "$PSScriptRoot\$zipFilename"
}
}
# logout of bitwaren to ensure the session is destroyed
& $bw logout
# remove all the variables
Remove-Variable -Name * -ErrorAction SilentlyContinue
bw logout
<#
# Restore of attachements
cd C:\users\jgaunt\Git\bitwardenbackup\attachments
bw status
$folders = Get-childItem -Directory
$items = bw list items | convertfrom-json
$array = @()
foreach ($folder in $folders) {
foreach ($item in $items) {
if ($folder.name -eq $item.name -and $item.type -gt 1) {
#$array += bw get item $item.id | convertfrom-json
$attachements = Get-ChildItem $folder
foreach ($attachement in $attachements) {
bw create attachment --file "$($attachement.FullName)" --itemid $item.id
}
Remove-Item -Recurse $folder
}
}
}
#>

567
bitwardenBackup.py Normal file
View File

@@ -0,0 +1,567 @@
# library needed
import sys
import os
import subprocess
import platform
import json
import getpass
import logging
import secrets
import base64
import optparse
import hmac as pyhmac
import datetime
import time
import shutil
from kmip.core import enums
from kmip.pie import client
def build_logger(level):
logger = logging.getLogger()
logger.setLevel(level)
formatter = logging.Formatter(
'%(asctime)s - %(levelname)s - %(message)s'
)
# log to file
fileHandler = logging.FileHandler(log_file)
fileHandler.setFormatter(formatter)
logger.addHandler(fileHandler)
# log to console
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(formatter)
logger.addHandler(consoleHandler)
return logger
def write_config_file(array, config_file):
logger.debug("Starting to write config file and encrypt contents")
logger.debug("Using config file: {}".format(config_file))
logger.debug("Converting config from array to json")
array_json = json.dumps(array)
logger.debug("Encrypting config json")
encrypted_array_json = encrypt(array_json)
logger.debug("Attempting to write encrypted config to file")
try:
f = open(config_file, "w")
f.write(encrypted_array_json)
f.close()
logger.debug("Successfully wrote encrypted config to file")
except Exception as e:
logger.error("Unable to write encrypted config to file. Error: {}".format(e))
sys.exit(-1)
logger.debug("Finshed writing config file and encrypting contents")
def read_config_file(config_file):
logger.debug("Starting to read config file and decrypt contents")
logger.debug("Using config file: {}".format(config_file))
logger.debug("Attempting to read encrypted config from file")
try:
with open(config_file) as f:
config = f.read()
logger.debug("Successfully read encrypted config from file")
except Exception as e:
logger.error("Unable to read encrypted config from file. Error: {}".format(e))
sys.exit(-1)
logger.debug("Decrypting config contents")
decrypted_array_json = decrypt(config)
logger.debug("Convert config from json to array")
array = json.loads(decrypted_array_json)
logger.debug("Finished reading config file and decrypting contents")
return array
def ask_for_confirmation(question):
logger.debug("Asking user for confirmation")
logger.debug("Question: {}".format(question))
print(question)
while True:
confirmation = input("y/n> ")
logger.debug("User answered: {}".format(confirmation))
if confirmation.casefold() == "y":
return True
elif confirmation.casefold() == "n":
return False
else:
print("This value must be one of the following characters: y, n.")
def create_encryption_key():
# Create an encryption key.
try:
key_id = client.create(
enums.CryptographicAlgorithm.AES,
256,
cryptographic_usage_mask=[
enums.CryptographicUsageMask.ENCRYPT,
enums.CryptographicUsageMask.DECRYPT
]
)
logger.debug("Successfully created a new encryption key.")
logger.debug("Encryption Key ID: {}".format(key_id))
except Exception as e:
logger.error(e)
sys.exit(-1)
# Activate the encryption key so that it can be used.
try:
client.activate(key_id)
logger.debug("Successfully activated the encryption key.")
return key_id
except Exception as e:
logger.error(e)
sys.exit(-1)
def create_hmac_key():
# Create an encryption key.
try:
key_id = client.create(
enums.CryptographicAlgorithm.AES,
256,
cryptographic_usage_mask=[
enums.CryptographicUsageMask.MAC_GENERATE,
enums.CryptographicUsageMask.MAC_VERIFY
]
)
logger.debug("Successfully created a new HMAC key.")
logger.debug("HMAC Key ID: {}".format(key_id))
except Exception as e:
logger.error(e)
sys.exit(-1)
# Activate the HMAC key so that it can be used.
try:
client.activate(key_id)
logger.debug("Successfully activated the HMAC key.")
return key_id
except Exception as e:
logger.error(e)
sys.exit(-1)
def encrypt(data):
try:
data = data.encode('UTF-8')
key_id = create_encryption_key()
iv = secrets.token_bytes(16)
cipher_text, autogenerated_iv = client.encrypt(
data,
uid=key_id,
cryptographic_parameters={
'cryptographic_algorithm':
enums.CryptographicAlgorithm.AES,
'block_cipher_mode': enums.BlockCipherMode.CBC,
'padding_method': enums.PaddingMethod.ANSI_X923
},
iv_counter_nonce=(
iv
)
)
hmac_key_id, hmac = client.mac(
key_id.encode() + iv + cipher_text,
uid = create_hmac_key(),
algorithm = enums.CryptographicAlgorithm.HMAC_SHA512
)
logger.debug("Successfully encrypted the data.")
array = dict()
array['version'] = 1
array['cipher_key_id'] = key_id
array['cipher_text'] = base64.b64encode(cipher_text).decode()
array['iv'] = base64.b64encode(iv).decode()
array['hmac_key_id'] = hmac_key_id
array['hmac'] = base64.b64encode(hmac).decode()
logger.debug("Dict of info: {}".format(array))
array_json = json.dumps(array)
array_json_b64 = base64.b64encode(array_json.encode('utf-8')).decode()
return array_json_b64
except Exception as e:
logger.error(e)
def decrypt(data):
array_json = base64.b64decode(data)
array = json.loads(array_json)
if array['version'] == 1:
return decrypt_v1(array)
else:
logger.error("Unable to detemine encryption version.")
return False
def decrypt_v1(array):
try:
logger.debug("Dict of info: {}".format(array))
key_id = array['cipher_key_id']
iv = base64.b64decode(array['iv'])
cipher_text = base64.b64decode(array['cipher_text'])
hmac_key_id = array['hmac_key_id']
hmac = base64.b64decode(array['hmac'])
hmac_key_id_test, hmac_test = client.mac(
key_id.encode() + iv + cipher_text,
uid = hmac_key_id,
algorithm = enums.CryptographicAlgorithm.HMAC_SHA512
)
if pyhmac.compare_digest(hmac, hmac_test):
logger.debug("HMAC matches.")
else:
logger.error("HMAC does not match, data is corrupted/tampered.")
sys.exit(-1)
plain_text = client.decrypt(
cipher_text,
uid=key_id,
cryptographic_parameters={
'cryptographic_algorithm':
enums.CryptographicAlgorithm.AES,
'block_cipher_mode': enums.BlockCipherMode.CBC,
'padding_method': enums.PaddingMethod.ANSI_X923
},
iv_counter_nonce=(
iv
)
)
logger.debug("Successfully decrypted the data.")
plain_text = plain_text.decode('utf-8')
return plain_text
except Exception as e:
logger.error(e)
def new_account_details():
print("Requesting account details to add to config.")
account_email_address = input("Please enter Bitwarden account email address: ")
account_api_client_id = input("Please enter Bitwarden account API client ID: ")
while True:
account_api_secret = getpass.getpass("Please enter Bitwarden account API secret: ")
account_api_secret2 = getpass.getpass("Please confirm Bitwarden account API secret: ")
if account_api_secret == account_api_secret2:
break
else:
print("The Bitwarden account API secrets do not match, please try again.")
while True:
account_vault_password = getpass.getpass("Please enter Bitwarden account vault password: ")
account_vault_password2 = getpass.getpass("Please confirm Bitwarden account vault password: ")
if account_vault_password == account_vault_password2:
break
else:
print("The Bitwarden account vault passwords do not match, please try again.")
array = dict()
array[account_email_address] = dict()
array[account_email_address]["account_api_client_id"] = account_api_client_id
array[account_email_address]["account_api_secret"] = account_api_secret
array[account_email_address]["account_vault_password"] = account_vault_password
return array
def edit_account_details(accounts, email):
if ask_for_confirmation("Would you like to edit the Bitwarden account email address?\nCurrent Value: {}".format(email)):
account_email_address = input("Please enter Bitwarden account email address: ")
else:
account_email_address = email
if ask_for_confirmation("Would you like to edit the Bitwarden account API client ID?\nCurrent Value: {}".format(accounts[email]['account_api_client_id'])):
account_api_client_id = input("Please enter Bitwarden account API client ID: ")
else:
account_api_client_id = accounts[email]['account_api_client_id']
if ask_for_confirmation("Would you like to edit the Bitwarden account API secret?"):
while True:
account_api_secret = getpass.getpass("Please enter Bitwarden account API secret: ")
account_api_secret2 = getpass.getpass("Please confirm Bitwarden account API secret: ")
if account_api_secret == account_api_secret2:
break
else:
print("The Bitwarden account API secrets do not match, please try again.")
else:
account_api_secret = accounts[email]['account_api_secret']
if ask_for_confirmation("Would you like to edit the Bitwarden account vault password?"):
while True:
account_vault_password = getpass.getpass("Please enter Bitwarden account vault password: ")
account_vault_password2 = getpass.getpass("Please confirm Bitwarden account vault password: ")
if account_vault_password == account_vault_password2:
break
else:
print("The Bitwarden account vault passwords do not match, please try again.")
else:
account_vault_password = accounts[email]['account_vault_password']
array = dict()
array[account_email_address] = dict()
array[account_email_address]["account_api_client_id"] = account_api_client_id
array[account_email_address]["account_api_secret"] = account_api_secret
array[account_email_address]["account_vault_password"] = account_vault_password
return array
def select_account(accounts, wording = "edit"):
print("Which account would you like to {}:".format(wording))
print(" ")
emails = list(accounts)
for i in range(0, len(accounts)):
pretty_number = i + 1
print("{}) {}".format(pretty_number, emails[i]))
print(" ")
while True:
account_to_modify = int(input("Please enter number relating to the account you wish to {}: ".format(wording))) - 1
try:
return emails[account_to_modify]
except IndexError as error:
print("you entered a number out of range, please try again")
if __name__ == "__main__":
# Build and parse arguments
parser = optparse.OptionParser(
usage="%prog [options]",
description="Run Bitwarden backup opteration. This will produce an encrypted zip/tar with exported CSV, JSON, and attachements.")
parser.add_option(
"-c",
"--config",
action="store_true",
dest="config",
help="Edit Bitwarden account configuration."
)
parser.add_option (
"-v",
"--verbose",
action="store_true",
dest="debug",
help="Output debug/verbose info to the console for troubleshooting."
)
parser.add_option (
"--no-encryption",
action="store_true",
dest="no_encrypt",
help="Will only zip up export and will NOT encrypt anything."
)
opts, args = parser.parse_args(sys.argv[1:])
os_detected = platform.system()
script_directory = os.path.dirname(os.path.realpath(__file__))
working_directory = os.path.join(script_directory, "working")
exports_directory = os.path.join(script_directory, "exports")
script_name = os.path.basename(__file__)
secrets_config_file = os.path.join(script_directory, "secrets.config")
pykmip_client_config_file = os.path.join(script_directory, "conf", "client.conf")
log_file = os.path.join(script_directory, "log.log")
datetime_string = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
if opts.debug:
logger = build_logger(logging.DEBUG)
else:
logger = build_logger(logging.INFO)
if os_detected == "Windows":
bitwarden_cli_executable = os.path.join(script_directory, "lib", "Bitwarden CLI", "bw.exe")
gpg_executable = os.path.join(script_directory, "lib", "gpg", "bin", "gpg.exe")
sdelete_executable = os.path.join(script_directory, "lib", "sdelete.exe")
elif os_detected == "Linux":
bitwarden_cli_executable = os.path.join(script_directory, "lib", "Bitwarden CLI", "bw_linux")
gpg_executable = "gpg"
#elif os_detected == "macOS":
# bitwarden_cli_executable = os.path.join(script_directory, "lib", "Bitwarden CLI", "bw_macOS")
else:
print("Your OS is not supported. Only Windows, Linux, and macOS are supported. Those are the only three supported OSes for the Bitwarden CLI.")
print("Detected OS: {0}".format(os_detected))
sys.exit(1)
client = client.ProxyKmipClient(config_file=pykmip_client_config_file)
client.open()
#print(encrypt(client, "test"))
if opts.config:
while True:
if not os.path.exists(secrets_config_file):
print("No Bitwarden accounts found, do you want to make a new one?")
print(" ")
print("n) New account")
print("q) Quit config")
while True:
user_input = input("n/q> ")
if user_input.casefold() == "n":
account_details = new_account_details()
write_config_file(account_details, secrets_config_file)
break
elif user_input.casefold() == "q":
sys.exit(0)
else:
print("This value must be one of the following characters: n, q.")
accounts = read_config_file(secrets_config_file)
print("Current Bitwarden accounts:")
print(" ")
for account in accounts:
print(account)
print(" ")
print("e) Edit account")
print("n) New account")
print("d) Delete account")
print("q) Quit config")
while True:
user_input = input("e/n/d/q> ")
# Editing an account
if user_input.casefold() == "e":
account_to_edit = select_account(accounts)
account_details = edit_account_details(accounts, account_to_edit)
del accounts[account_to_edit]
accounts.update(account_details)
write_config_file(accounts, secrets_config_file)
break
# Createing a new account
elif user_input.casefold() == "n":
account_details = new_account_details()
accounts.update(account_details)
write_config_file(accounts, secrets_config_file)
break
# Deleting an account
elif user_input.casefold() == "d":
account_to_delete = select_account(accounts, "delete")
if not ask_for_confirmation("Are you sure you wish to delete {} account? ".format(account_to_delete)):
break
del accounts[account_to_delete]
if len(accounts) == 0:
# no more accounts, remove secrets file
os.remove(secrets_config_file)
else:
write_config_file(accounts, secrets_config_file)
break
# Quit the config
elif user_input.casefold() == "q":
sys.exit(0)
# Catch all for non-valid characters
else:
print("This value must be one of the following characters: e, n, d, q.")
#json.loads((subprocess.check_output(['bw.exe','status'])).decode())['status']
if not os.path.exists(secrets_config_file):
print("No configuration file found. Please run {} -c to configure your accounts.".format(script_name))
sys.exit(-1)
accounts = read_config_file(secrets_config_file)
emails = list(accounts)
for email in emails:
vault_password = accounts[email]['account_vault_password']
os.environ["BW_CLIENTID"] = accounts[email]['account_api_client_id']
os.environ["BW_CLIENTSECRET"] = accounts[email]['account_api_secret']
# login to Bitwarden
logger.info("Trying to login to Bitwarden as {}".format(email))
bitwarden_login_output = subprocess.run([bitwarden_cli_executable, 'login', '--apikey', '--raw'], capture_output=True)
logger.debug((bitwarden_login_output.stdout).decode())
bitwarden_status = json.loads(((subprocess.run([bitwarden_cli_executable, 'status'], capture_output=True)).stdout).decode())
logger.debug("Bitwarden Status: {}".format(bitwarden_status))
if bitwarden_status['status'] == "locked":
logger.info("Successfully Logged in")
bitwarden_unlock_output = subprocess.run([bitwarden_cli_executable, 'unlock', vault_password, '--raw', '--nointeraction'], capture_output=True)
bitwarden_session_key = (bitwarden_unlock_output.stdout).decode()
if bitwarden_session_key:
# logger.debug("Session key: {}".format(bitwarden_session_key))
logger.info("Successfully unlocked vault")
os.environ["BW_SESSION"] = bitwarden_session_key
# export to csv and json
logger.info("Exporting vault to both CSV and JSON files")
logger.debug("Exporting vault to CSV")
file_name = 'Bitwarden {} Export {}'.format(email, datetime_string)
while True:
logger.debug((subprocess.run([bitwarden_cli_executable, 'export', '--output', os.path.join(working_directory, '{}.csv'.format(file_name)) , '--format', 'csv'], capture_output=True).stdout).decode())
time.sleep(1)
file_size = os.path.getsize(os.path.join(working_directory, '{}.csv'.format(file_name)))
if (file_size > 0):
break
else:
logger.info("CSV export did not run correctly, running export again")
if os.path.exists(os.path.join(working_directory, '{}.csv'.format(file_name))):
os.remove(os.path.join(working_directory, '{}.csv'.format(file_name)))
time.sleep(5)
logger.debug("Exporting vault to JSON")
while True:
logger.debug((subprocess.run([bitwarden_cli_executable, 'export', '--output', os.path.join(working_directory, '{}.json'.format(file_name)), '--format', 'json'], capture_output=True).stdout).decode())
time.sleep(1)
file_size = os.path.getsize(os.path.join(working_directory, '{}.json'.format(file_name)))
if (file_size > 56):
break
else:
logger.info("JSON export did not run correctly, running export again")
if os.path.exists(os.path.join(working_directory, '{}.json'.format(file_name))):
os.remove(os.path.join(working_directory, '{}.json'.format(file_name)))
time.sleep(5)
# looking for Organizations
# look for organizations
logger.info("Looking for Organizations")
bitwarden_organizations = json.loads(((subprocess.run([bitwarden_cli_executable, 'list', 'organizations'], capture_output=True)).stdout).decode())
logger.info("Found {} Organiztaions.".format(len(bitwarden_organizations)))
for organization in bitwarden_organizations:
logger.info("Exporting organization {} vault to both CSV and JSON files".format(organization['name']))
logger.debug("Exporting organization vault to CSV")
file_name = 'Bitwarden Organization {} Export {}'.format(organization['name'], datetime_string)
while True:
logger.debug((subprocess.run([bitwarden_cli_executable, 'export', '--organizationid', '{}'.format(organization['id']), '--output', os.path.join(working_directory, '{}.csv'.format(file_name)), '--format', 'csv'], capture_output=True).stdout).decode())
time.sleep(1)
file_size = os.path.getsize(os.path.join(working_directory, '{}.csv'.format(file_name)))
if (file_size > 0):
break
else:
logger.info("CSV export did not run correctly, running export again")
time.sleep(5)
logger.debug("Exporting organization vault to JSON")
while True:
logger.debug((subprocess.run([bitwarden_cli_executable, 'export', '--organizationid', '{}'.format(organization['id']), '--output', os.path.join(working_directory, '{}.json'.format(file_name)), '--format', 'json'], capture_output=True).stdout).decode())
time.sleep(1)
file_size = os.path.getsize(os.path.join(working_directory, '{}.json'.format(file_name)))
if (file_size > 56):
break
else:
logger.info("JSON export did not run correctly, running export again")
time.sleep(5)
logger.info("Downlading attachments...")
bitwarden_items = json.loads(((subprocess.run([bitwarden_cli_executable, 'list', 'items'], capture_output=True)).stdout).decode())
for item in bitwarden_items:
logger.debug("Working on item {} ({})".format(item['name'], item['id']))
if "attachments" in item:
logger.debug("Found {} attachments".format(len(item['attachments'])))
attachment_folder_name = os.path.join(working_directory, "attachments", item['name'])
for attachment in item['attachments']:
logger.debug("Downloading attachment ({}) with name {} to folder {}".format(attachment['id'], attachment['fileName'], attachment_folder_name))
logger.info((subprocess.run([bitwarden_cli_executable, 'get', 'attachment', attachment['id'], '--itemid', item['id'], '--output', os.path.join(attachment_folder_name, attachment['fileName'])], capture_output=True).stdout).decode())
time.sleep(1)
else:
logger.debug("Item has no attachments")
logger.info("Done downloading attachments")
logger.info("Zipping everything together...")
zip_filename = os.path.join(exports_directory, "Bitwarden Backup {} {}".format(email, datetime_string))
shutil.make_archive(zip_filename, format="zip", root_dir=working_directory)
if not opts.no_encrypt:
logger.debug((subprocess.run([gpg_executable, '--no-options', '--batch', '--passphrase', vault_password, '--symmetric', '--cipher-algo', 'AES256', '--digest-algo', 'SHA512', '--compression-algo', 'Uncompressed', '--output', zip_filename + '.zip.gpg', zip_filename + '.zip'], capture_output=True).stdout).decode())
logger.info("Securely deleting files")
if os_detected == "Windows":
# sdelete.exe .\working\ -p 5 -s
logger.debug((subprocess.run([sdelete_executable, '-p', '5', '-s', working_directory], capture_output=True).stdout).decode())
if not opts.no_encrypt:
logger.debug((subprocess.run([sdelete_executable, '-p', '5', zip_filename + ".zip"], capture_output=True).stdout).decode())
elif os_detected == "Linux":
# find <directory> -depth -type f -exec shred -v -n 1 -z -u {} \;
logger.debug((subprocess.run(['find', working_directory, '-depth', '-type', 'f', '-exec', 'shred', '-v', '-n', '5', '-u', '/{/}', '\/', ';'], capture_output=True).stdout).decode())
if not opts.no_encrypt:
logger.debug((subprocess.run(['shred', '-v', '-u', '-n', '5', zip_filename + '.zip'], capture_output=True).stdout).decode())
else:
logger.error((bitwarden_unlock_output.stderr).decode())
else:
logger.error("Unable to login to account, please check API credentials")
#logger.error((bitwarden_login_output.stderr).decode())
del vault_password
del os.environ['BW_CLIENTID']
del os.environ['BW_CLIENTSECRET']
if "BW_SESSION" in os.environ:
del os.environ["BW_SESSION"]
logger.info("Logging out of your Bitwarden account")
logger.debug((subprocess.run([bitwarden_cli_executable, 'logout'], capture_output=True).stdout).decode())
del accounts
del emails
client.close()
sys.exit(0)

11
conf/client.conf.sample Normal file
View File

@@ -0,0 +1,11 @@
# THIS IS A SAMPLE FILE, PLEASE COPY IT AND EDIT THE COPY
[client]
host=127.0.0.1
port=5696
certfile=kmip.crt
keyfile=kmip.key
ca_certs=kmip.crt
cert_reqs=CERT_REQUIRED
ssl_version=PROTOCOL_TLS
do_handshake_on_connect=True
suppress_ragged_eofs=True

BIN
lib/7-Zip/7za.dll Normal file

Binary file not shown.

BIN
lib/7-Zip/7za.exe Normal file

Binary file not shown.

BIN
lib/7-Zip/7zxa.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,2 +1,2 @@
gnupg
2.2.28
2.3.6

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,6 @@
/* gcrypt.h - GNU Cryptographic Library Interface -*- c -*-
* Copyright (C) 2012-2021 g10 Code GmbH
* Copyright (C) 2012-2022 g10 Code GmbH
* Copyright (C) 2013-2022 Jussi Kivilinna
* Copyright (C) 1998-2018 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
@@ -16,7 +17,6 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* File: src/gcrypt.h. Generated from gcrypt.h.in by configure.
*/
@@ -33,20 +33,11 @@
#include <sys/types.h>
#if defined _WIN32 || defined __WIN32__
# include <winsock2.h>
# include <ws2tcpip.h>
# include <time.h>
# ifndef __GNUC__
typedef long ssize_t;
typedef int pid_t;
# endif /*!__GNUC__*/
#else
# include <sys/socket.h>
# include <sys/time.h>
#
#endif /*!_WIN32*/
typedef int gcry_socklen_t;
#endif /*_WIN32*/
/* This is required for error code compatibility. */
#define _GCRY_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_GCRYPT
@@ -63,11 +54,11 @@ extern "C" {
return the same version. The purpose of this macro is to let
autoconf (using the AM_PATH_GCRYPT macro) check that this header
matches the installed library. */
#define GCRYPT_VERSION "1.8.8"
#define GCRYPT_VERSION "1.10.1"
/* The version number of this header. It may be used to handle minor
API incompatibilities. */
#define GCRYPT_VERSION_NUMBER 0x010808
#define GCRYPT_VERSION_NUMBER 0x010a01
/* Internal: We can't use the convenience macros for the multi
@@ -128,7 +119,7 @@ extern "C" {
#ifdef _GCRYPT_IN_LIBGCRYPT
#define _GCRY_ATTR_INTERNAL
#else
#define _GCRY_ATTR_INTERNAL _GCRY_GCC_ATTR_DEPRECATED
#define _GCRY_ATTR_INTERNAL _GCRY_GCC_ATTR_DEPRECATED
#endif
/* Wrappers for the libgpg-error library. */
@@ -333,7 +324,13 @@ enum gcry_ctl_cmds
GCRYCTL_DRBG_REINIT = 74,
GCRYCTL_SET_TAGLEN = 75,
GCRYCTL_GET_TAGLEN = 76,
GCRYCTL_REINIT_SYSCALL_CLAMP = 77
GCRYCTL_REINIT_SYSCALL_CLAMP = 77,
GCRYCTL_AUTO_EXPAND_SECMEM = 78,
GCRYCTL_SET_ALLOW_WEAK_KEY = 79,
GCRYCTL_SET_DECRYPTION_TAG = 80,
GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81,
GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82,
GCRYCTL_NO_FIPS_MODE = 83
};
/* Perform various operations defined by CMD. */
@@ -387,7 +384,7 @@ gcry_error_t gcry_sexp_build (gcry_sexp_t *retsexp, size_t *erroff,
/* Like gcry_sexp_build, but uses an array instead of variable
function arguments. */
gcry_error_t gcry_sexp_build_array (gcry_sexp_t *retsexp, size_t *erroff,
const char *format, void **arg_list);
const char *format, void **arg_list);
/* Release the S-expression object SEXP */
void gcry_sexp_release (gcry_sexp_t sexp);
@@ -588,6 +585,9 @@ gcry_mpi_t gcry_mpi_set (gcry_mpi_t w, const gcry_mpi_t u);
/* Store the unsigned integer value U in W. */
gcry_mpi_t gcry_mpi_set_ui (gcry_mpi_t w, unsigned long u);
/* Store U as an unsigned int at W or return GPG_ERR_ERANGE. */
gpg_error_t gcry_mpi_get_ui (unsigned int *w, gcry_mpi_t u);
/* Swap the values of A and B. */
void gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t b);
@@ -841,6 +841,7 @@ gcry_mpi_t _gcry_mpi_get_const (int no);
#define mpi_snatch( w, u) gcry_mpi_snatch( (w), (u) )
#define mpi_set( w, u) gcry_mpi_set( (w), (u) )
#define mpi_set_ui( w, u) gcry_mpi_set_ui( (w), (u) )
#define mpi_get_ui( w, u) gcry_mpi_get_ui( (w), (u) )
#define mpi_abs( w ) gcry_mpi_abs( (w) )
#define mpi_neg( w, u) gcry_mpi_neg( (w), (u) )
#define mpi_cmp( u, v ) gcry_mpi_cmp( (u), (v) )
@@ -940,7 +941,9 @@ enum gcry_cipher_algos
GCRY_CIPHER_SALSA20 = 313,
GCRY_CIPHER_SALSA20R12 = 314,
GCRY_CIPHER_GOST28147 = 315,
GCRY_CIPHER_CHACHA20 = 316
GCRY_CIPHER_CHACHA20 = 316,
GCRY_CIPHER_GOST28147_MESH = 317, /* With CryptoPro key meshing. */
GCRY_CIPHER_SM4 = 318
};
/* The Rijndael algorithm is basically AES, so provide some macros. */
@@ -967,7 +970,10 @@ enum gcry_cipher_modes
GCRY_CIPHER_MODE_POLY1305 = 10, /* Poly1305 based AEAD mode. */
GCRY_CIPHER_MODE_OCB = 11, /* OCB3 mode. */
GCRY_CIPHER_MODE_CFB8 = 12, /* Cipher feedback (8 bit mode). */
GCRY_CIPHER_MODE_XTS = 13 /* XTS mode. */
GCRY_CIPHER_MODE_XTS = 13, /* XTS mode. */
GCRY_CIPHER_MODE_EAX = 14, /* EAX mode. */
GCRY_CIPHER_MODE_SIV = 15, /* SIV mode. */
GCRY_CIPHER_MODE_GCM_SIV = 16 /* GCM-SIV mode. */
};
/* Flags used with the open function. */
@@ -976,7 +982,8 @@ enum gcry_cipher_flags
GCRY_CIPHER_SECURE = 1, /* Allocate in secure memory. */
GCRY_CIPHER_ENABLE_SYNC = 2, /* Enable CFB sync mode. */
GCRY_CIPHER_CBC_CTS = 4, /* Enable CBC cipher text stealing (CTS). */
GCRY_CIPHER_CBC_MAC = 8 /* Enable CBC message auth. code (MAC). */
GCRY_CIPHER_CBC_MAC = 8, /* Enable CBC message auth. code (MAC). */
GCRY_CIPHER_EXTENDED = 16 /* Enable extended AES-WRAP. */
};
/* GCM works only with blocks of 128 bits */
@@ -991,6 +998,9 @@ enum gcry_cipher_flags
/* XTS works only with blocks of 128 bits. */
#define GCRY_XTS_BLOCK_LEN (128 / 8)
/* SIV and GCM-SIV works only with blocks of 128 bits */
#define GCRY_SIV_BLOCK_LEN (128 / 8)
/* Create a handle for algorithm ALGO to be used in MODE. FLAGS may
be given as an bitwise OR of the gcry_cipher_flags values. */
gcry_error_t gcry_cipher_open (gcry_cipher_hd_t *handle,
@@ -1093,6 +1103,11 @@ size_t gcry_cipher_get_algo_blklen (int algo);
#define gcry_cipher_test_algo(a) \
gcry_cipher_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL )
/* Setup tag for decryption (for SIV and GCM-SIV mode). */
#define gcry_cipher_set_decryption_tag(a, tag, taglen) \
gcry_cipher_ctl ((a), GCRYCTL_SET_DECRYPTION_TAG, \
(void *)(tag), (taglen))
/************************************
* *
@@ -1192,6 +1207,28 @@ gcry_sexp_t gcry_pk_get_param (int algo, const char *name);
/* Return an S-expression representing the context CTX. */
gcry_error_t gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp,
int mode, gcry_ctx_t ctx);
/************************************
* *
* Modern ECC Functions *
* *
************************************/
/* The curves we support. */
enum gcry_ecc_curves
{
GCRY_ECC_CURVE25519 = 1,
GCRY_ECC_CURVE448 = 2
};
/* Get the length of point to prepare buffer for the result. */
unsigned int gcry_ecc_get_algo_keylen (int curveid);
/* Convenience function to compute scalar multiplication of the
* Montgomery form of curve. */
gpg_error_t gcry_ecc_mul_point (int curveid, unsigned char *result,
const unsigned char *scalar,
const unsigned char *point);
@@ -1241,7 +1278,10 @@ enum gcry_md_algos
GCRY_MD_BLAKE2S_256 = 322,
GCRY_MD_BLAKE2S_224 = 323,
GCRY_MD_BLAKE2S_160 = 324,
GCRY_MD_BLAKE2S_128 = 325
GCRY_MD_BLAKE2S_128 = 325,
GCRY_MD_SM3 = 326,
GCRY_MD_SHA512_256 = 327,
GCRY_MD_SHA512_224 = 328
};
/* Flags used with the open function. */
@@ -1408,6 +1448,7 @@ typedef struct gcry_mac_handle *gcry_mac_hd_t;
enum gcry_mac_algos
{
GCRY_MAC_NONE = 0,
GCRY_MAC_GOST28147_IMIT = 1,
GCRY_MAC_HMAC_SHA256 = 101,
GCRY_MAC_HMAC_SHA224 = 102,
@@ -1427,6 +1468,18 @@ enum gcry_mac_algos
GCRY_MAC_HMAC_SHA3_256 = 116,
GCRY_MAC_HMAC_SHA3_384 = 117,
GCRY_MAC_HMAC_SHA3_512 = 118,
GCRY_MAC_HMAC_GOSTR3411_CP = 119,
GCRY_MAC_HMAC_BLAKE2B_512 = 120,
GCRY_MAC_HMAC_BLAKE2B_384 = 121,
GCRY_MAC_HMAC_BLAKE2B_256 = 122,
GCRY_MAC_HMAC_BLAKE2B_160 = 123,
GCRY_MAC_HMAC_BLAKE2S_256 = 124,
GCRY_MAC_HMAC_BLAKE2S_224 = 125,
GCRY_MAC_HMAC_BLAKE2S_160 = 126,
GCRY_MAC_HMAC_BLAKE2S_128 = 127,
GCRY_MAC_HMAC_SM3 = 128,
GCRY_MAC_HMAC_SHA512_256 = 129,
GCRY_MAC_HMAC_SHA512_224 = 130,
GCRY_MAC_CMAC_AES = 201,
GCRY_MAC_CMAC_3DES = 202,
@@ -1439,6 +1492,7 @@ enum gcry_mac_algos
GCRY_MAC_CMAC_RFC2268 = 209,
GCRY_MAC_CMAC_IDEA = 210,
GCRY_MAC_CMAC_GOST28147 = 211,
GCRY_MAC_CMAC_SM4 = 212,
GCRY_MAC_GMAC_AES = 401,
GCRY_MAC_GMAC_CAMELLIA = 402,
@@ -1538,7 +1592,16 @@ enum gcry_kdf_algos
GCRY_KDF_ITERSALTED_S2K = 19,
GCRY_KDF_PBKDF1 = 33,
GCRY_KDF_PBKDF2 = 34,
GCRY_KDF_SCRYPT = 48
GCRY_KDF_SCRYPT = 48,
GCRY_KDF_ARGON2 = 64,
GCRY_KDF_BALLOON = 65
};
enum gcry_kdf_subalgo_argon2
{
GCRY_KDF_ARGON2D = 0,
GCRY_KDF_ARGON2I = 1,
GCRY_KDF_ARGON2ID = 2
};
/* Derive a key from a passphrase. */
@@ -1548,8 +1611,33 @@ gpg_error_t gcry_kdf_derive (const void *passphrase, size_t passphraselen,
unsigned long iterations,
size_t keysize, void *keybuffer);
/* Another API to derive a key from a passphrase. */
typedef struct gcry_kdf_handle *gcry_kdf_hd_t;
typedef void (*gcry_kdf_job_fn_t) (void *priv);
typedef int (*gcry_kdf_dispatch_job_fn_t) (void *jobs_context,
gcry_kdf_job_fn_t job_fn,
void *job_priv);
typedef int (*gcry_kdf_wait_all_jobs_fn_t) (void *jobs_context);
/* Exposed structure for KDF computation to decouple thread functionality. */
typedef struct gcry_kdf_thread_ops
{
void *jobs_context;
gcry_kdf_dispatch_job_fn_t dispatch_job;
gcry_kdf_wait_all_jobs_fn_t wait_all_jobs;
} gcry_kdf_thread_ops_t;
gcry_error_t gcry_kdf_open (gcry_kdf_hd_t *hd, int algo, int subalgo,
const unsigned long *param, unsigned int paramlen,
const void *passphrase, size_t passphraselen,
const void *salt, size_t saltlen,
const void *key, size_t keylen,
const void *ad, size_t adlen);
gcry_error_t gcry_kdf_compute (gcry_kdf_hd_t h,
const gcry_kdf_thread_ops_t *ops);
gcry_error_t gcry_kdf_final (gcry_kdf_hd_t h, size_t resultlen, void *result);
void gcry_kdf_close (gcry_kdf_hd_t h);
/************************************
* *
@@ -1600,8 +1688,7 @@ void *gcry_random_bytes (size_t nbytes, enum gcry_random_level level)
_GCRY_GCC_ATTR_MALLOC;
/* Return NBYTES of allocated random using a random numbers of quality
LEVEL. The random numbers are created returned in "secure"
memory. */
LEVEL. The random is returned in "secure" memory. */
void *gcry_random_bytes_secure (size_t nbytes, enum gcry_random_level level)
_GCRY_GCC_ATTR_MALLOC;
@@ -1784,6 +1871,32 @@ int gcry_is_secure (const void *a) _GCRY_GCC_ATTR_PURE;
/* Return true if Libgcrypt is in FIPS mode. */
#define gcry_fips_mode_active() !!gcry_control (GCRYCTL_FIPS_MODE_P, 0)
/* Variant of gcry_pk_sign which takes as additional parameter a HD
* handle for hash and an optional context. The hash algorithm used by the
* handle needs to be enabled and input needs to be supplied beforehand.
* DATA-TMPL specifies a template to compose an S-expression to be signed.
* A template should include '(hash %s %b)' or '(hash ALGONAME %b)'.
* For the former case, '%s' is substituted by the string of algorithm
* of gcry_md_get_algo (HD) and when gcry_md_read is called, ALGO=0 is
* used internally. For the latter case, hash algorithm by ALGONAME
* is used when gcry_md_read is called internally.
* The hash handle must not yet been finalized; the function
* takes a copy of the state and does a finalize on the copy. This
* function shall be used if a policy requires that hashing and signing
* is done by the same function. CTX is currently not used and should
* be passed as NULL. */
gcry_error_t gcry_pk_hash_sign (gcry_sexp_t *result,
const char *data_tmpl, gcry_sexp_t skey,
gcry_md_hd_t hd, gcry_ctx_t ctx);
/* Variant of gcry_pk_verify which takes as additional parameter a HD
* handle for hash and an optional context. Similar to gcry_pk_hash_sign. */
gcry_error_t gcry_pk_hash_verify (gcry_sexp_t sigval,
const char *data_tmpl, gcry_sexp_t pkey,
gcry_md_hd_t hd, gcry_ctx_t ctx);
gcry_error_t gcry_pk_random_override_new (gcry_ctx_t *r_ctx,
const unsigned char *p, size_t len);
#if 0 /* (Keep Emacsens' auto-indent happy.) */
{

View File

@@ -66,12 +66,12 @@
#include <stdarg.h>
/* The version string of this header. */
#define GPG_ERROR_VERSION "1.42"
#define GPGRT_VERSION "1.42"
#define GPG_ERROR_VERSION "1.45"
#define GPGRT_VERSION "1.45"
/* The version number of this header. */
#define GPG_ERROR_VERSION_NUMBER 0x012a00
#define GPGRT_VERSION_NUMBER 0x012a00
#define GPG_ERROR_VERSION_NUMBER 0x012d00
#define GPGRT_VERSION_NUMBER 0x012d00
#ifdef __GNUC__
@@ -1103,6 +1103,22 @@ size_t gpgrt_w32_iconv (gpgrt_w32_iconv_t cd,
# define iconv(a,b,c,d,e) gpgrt_w32_iconv ((a),(b),(c),(d),(e))
#endif /*GPGRT_ENABLE_W32_ICONV_MACROS*/
/* Release a wchar_t * buffer. */
void gpgrt_free_wchar (wchar_t *wstring);
/* Convert an UTF-8 encoded file name to wchar.
* Prepend a '\\?\' prefix if needed. */
wchar_t *gpgrt_fname_to_wchar (const char *fname);
/* Convert an UTF8 string to a WCHAR string. Caller should use
* gpgrt_free_wchar to release the result.
* Returns NULL on error and sets ERRNO. */
wchar_t *gpgrt_utf8_to_wchar (const char *string);
/* Convert a WCHAR string to UTF-8. Caller should use gpgrt_free to
* release the result. Returns NULL on error and sets ERRNO. */
char *gpgrt_wchar_to_utf8 (const wchar_t *wstring);
/* Query a string in the registry. */
char *gpgrt_w32_reg_query_string (const char *root,
const char *dir,
@@ -1889,7 +1905,8 @@ typedef struct
#define ARGPARSE_FLAG_USER 2048 /* Use user config file. */
#define ARGPARSE_FLAG_VERBOSE 4096 /* Print additional argparser info. */
#define ARGPARSE_FLAG_USERVERS 8192 /* Try version-ed user config files. */
#define ARGPARSE_FLAG_WITHATTR 16384 /* Return attribute bits. */
#define ARGPARSE_FLAG_WITHATTR 16384 /* Return attribute bits. (Make sure */
/* to act upon ARGPARSE_OPT_IGNORE.) */
/* Constants for (gpgrt_argparse_t).err. */
#define ARGPARSE_PRINT_WARNING 1 /* Print a diagnostic. */

View File

@@ -42,11 +42,11 @@ extern "C" {
* instead. The purpose of this macro is to let autoconf (using the
* AM_PATH_GPGME macro) check that this header matches the installed
* library. */
#define GPGME_VERSION "1.15.1"
#define GPGME_VERSION "1.17.1"
/* The version number of this header. It may be used to handle minor
* API incompatibilities. */
#define GPGME_VERSION_NUMBER 0x010f01
#define GPGME_VERSION_NUMBER 0x011101
/* System specific typedefs. */
@@ -414,8 +414,8 @@ gpgme_pinentry_mode_t;
#define GPGME_EXPORT_MODE_SECRET 16
#define GPGME_EXPORT_MODE_RAW 32
#define GPGME_EXPORT_MODE_PKCS12 64
#define GPGME_EXPORT_MODE_NOUID 128 /* Experimental(!)*/
#define GPGME_EXPORT_MODE_SSH 256
#define GPGME_EXPORT_MODE_SECRET_SUBKEY 512
typedef unsigned int gpgme_export_mode_t;
@@ -636,7 +636,13 @@ struct _gpgme_key_sig
unsigned int exportable : 1;
/* Internal to GPGME, do not use. */
unsigned int _unused : 28;
unsigned int _unused : 12;
/* The depth of a trust signature, 0 if no trust signature. */
unsigned int trust_depth : 8;
/* The trust value of a trust signature, 0 if no trust signature. */
unsigned int trust_value : 8;
/* The public key algorithm used to create the signature. */
gpgme_pubkey_algo_t pubkey_algo;
@@ -683,6 +689,9 @@ struct _gpgme_key_sig
/* Internal to GPGME, do not use. */
gpgme_sig_notation_t _last_notation;
/* The scope of a trust signature. Might be NULL. */
char *trust_scope;
};
typedef struct _gpgme_key_sig *gpgme_key_sig_t;
@@ -1737,6 +1746,12 @@ gpgme_error_t gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata);
gpgme_error_t gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t keys[]);
gpgme_error_t gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t keys[]);
/* Import the keys given by the array KEYIDS from a keyserver into the
* keyring. */
gpgme_error_t gpgme_op_receive_keys_start (gpgme_ctx_t ctx,
const char *keyids[]);
gpgme_error_t gpgme_op_receive_keys (gpgme_ctx_t ctx, const char *keyids[]);
/* Export the keys found by PATTERN into KEYDATA. */
gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern,
@@ -1914,6 +1929,7 @@ gpgme_error_t gpgme_op_delete_ext (gpgme_ctx_t ctx, const gpgme_key_t key,
#define GPGME_KEYSIGN_LOCAL (1 << 7) /* Create a local signature. */
#define GPGME_KEYSIGN_LFSEP (1 << 8) /* Indicate LF separated user ids. */
#define GPGME_KEYSIGN_NOEXPIRE (1 << 9) /* Force no expiration. */
#define GPGME_KEYSIGN_FORCE (1 << 10) /* Force creation. */
/* Sign the USERID of KEY using the current set of signers. */
@@ -2471,6 +2487,11 @@ char *gpgme_addrspec_from_uid (const char *uid);
* Deprecated types, constants and functions.
*/
/* This is a former experimental only features. The constant is
* provided to not break existing code in the compiler phase. */
#define GPGME_EXPORT_MODE_NOUID 128 /* Do not use! */
/* The possible stati for gpgme_op_edit. The use of that function and
* these status codes are deprecated in favor of gpgme_op_interact. */
typedef enum

Binary file not shown.

Binary file not shown.

Binary file not shown.

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
pykmip
secure_delete