Compare commits
10 Commits
master
...
ben/howto-
Author | SHA1 | Date | |
---|---|---|---|
|
1e34141f67 | ||
|
dda54cc851 | ||
|
34308fe1fc | ||
|
dea1ccbc02 | ||
|
27ae87c7cf | ||
|
94a0f66376 | ||
|
bb8153269b | ||
|
aa4875bd06 | ||
|
f64d259e1d | ||
|
f0063afa71 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -48,6 +48,11 @@ nosetests.xml
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# DITA XML output
|
||||
temp/
|
||||
out/
|
||||
*.bak
|
||||
|
||||
# Assorted Apple crap
|
||||
default.profraw
|
||||
.DS_Store
|
||||
|
9
lang/python/docs/dita/gpgme-python-howto-footer.xhtml
Normal file
9
lang/python/docs/dita/gpgme-python-howto-footer.xhtml
Normal file
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<div>Copyright © Benjamin D. McGinnes, 2018<br />for the <a href="https://gnupg.org/" target="_blank">GnuPG Project</a></div>
|
||||
</body>
|
||||
</html>
|
98
lang/python/docs/dita/gpgme-python-howto.ditamap
Normal file
98
lang/python/docs/dita/gpgme-python-howto.ditamap
Normal file
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE bookmap PUBLIC "-//OASIS//DTD DITA BookMap//EN" "bookmap.dtd">
|
||||
<bookmap xml:lang="en-GB">
|
||||
<booktitle>
|
||||
<mainbooktitle>GPGME Python Bindings HOWTO</mainbooktitle>
|
||||
</booktitle>
|
||||
<bookmeta>
|
||||
<author>Ben McGinnes</author>
|
||||
<authorinformation>
|
||||
<personinfo>
|
||||
<namedetails>
|
||||
<personname id="author" name="Ben McGinnes"/>
|
||||
</namedetails>
|
||||
<emailaddresses id="author-email" name="ben@gnupg.org"/>
|
||||
</personinfo>
|
||||
<organizationinfo>
|
||||
<emailaddresses>
|
||||
<emailaddress id="gnupg-devel" name="gnupg-devel@gnupg.org"/>
|
||||
</emailaddresses>
|
||||
<urls>
|
||||
<url id="web" name="https://gnupg.org"/>
|
||||
</urls>
|
||||
</organizationinfo>
|
||||
</authorinformation>
|
||||
</bookmeta>
|
||||
<frontmatter>
|
||||
<draftintro id="draft" href="howto/version-info.dita"/>
|
||||
</frontmatter>
|
||||
<part id="part-1" href="howto/part-1.dita">
|
||||
<topicref id="intro" href="howto/part01/introduction.dita">
|
||||
<topicref id="py2v3" href="howto/part01/python2-vs-python3.dita"/>
|
||||
<topicref id="examples" href="howto/part01/examples.dita"/>
|
||||
</topicref>
|
||||
<topicref id="docsrc" href="howto/part01/docs-source.dita"/>
|
||||
</part>
|
||||
<part id="part-2" href="howto/part-2.dita">
|
||||
<topicref id="gpgme-concepts" href="howto/part02/gpgme-concepts.dita">
|
||||
<topicref id="c-api" href="howto/part02/c-api.dita"/>
|
||||
<topicref id="python-bindings" href="howto/part02/python-bindings.dita"/>
|
||||
<topicref id="py-diffs" href="howto/part02/differences-to-others.dita">
|
||||
<topicref id="vinay-sajip" href="howto/part02/python-gnupg.dita"/>
|
||||
<topicref id="isis-lovecruft" href="howto/part02/isis-gnupg.dita"/>
|
||||
<topicref id="martin-albrecht" href="howto/part02/pyme.dita"/>
|
||||
</topicref>
|
||||
</topicref>
|
||||
<topicref id="install" href="howto/part02/installation.dita">
|
||||
<topicref id="no-pypi" href="howto/part02/no-pypi.dita"/>
|
||||
<topicref id="requirements" href="howto/part02/requirements.dita"/>
|
||||
<topicref id="installing" href="howto/part02/installing.dita"/>
|
||||
</topicref>
|
||||
<topicref id="fundamentals" href="howto/part02/fundamentals.dita">
|
||||
<topicref id="for-the-wicked" href="howto/part02/no-rest.dita"/>
|
||||
<topicref id="excession" href="howto/part02/context.dita"/>
|
||||
</topicref>
|
||||
</part>
|
||||
<part id="part-3" href="howto/part-3.dita">
|
||||
<topicref id="key-select" href="howto/part03/key-selection.dita">
|
||||
<topicref id="key-count" href="howto/part03/key-counting.dita"/>
|
||||
</topicref>
|
||||
<topicref id="get-key" href="howto/part03/get-key.dita"/>
|
||||
<topicref id="import-key" href="howto/part03/importing.dita"/>
|
||||
<topicref id="export-key" href="howto/part03/exporting.dita">
|
||||
<topicref id="export-key-pub" href="howto/part03/exporting-pubkeys.dita"/>
|
||||
<topicref id="export-key-sec" href="howto/part03/exporting-seckeys.dita"/>
|
||||
</topicref>
|
||||
</part>
|
||||
<part id="part-4" href="howto/part-4.dita">
|
||||
<topicref id="basics" href="howto/part04/basic-functions.dita"/>
|
||||
<topicref id="encryption" href="howto/part04/encryption.dita">
|
||||
<topicref id="encrypt-to-one" href="howto/part04/encrypt-to-one.dita"/>
|
||||
<topicref id="encrypt-to-many" href="howto/part04/encrypt-to-many.dita"/>
|
||||
</topicref>
|
||||
<topicref id="decryption" href="howto/part04/decryption.dita"/>
|
||||
<topicref id="signing" href="howto/part04/signing.dita">
|
||||
<topicref id="sign-key-select" href="howto/part04/signing-key-selection.dita"/>
|
||||
<topicref id="signing-default" href="howto/part04/default-signing.dita"/>
|
||||
<topicref id="signing-detach" href="howto/part04/detached-signing.dita"/>
|
||||
<topicref id="signing-clear" href="howto/part04/clear-signing.dita"/>
|
||||
</topicref>
|
||||
<topicref id="verification" href="howto/part04/verification.dita"/>
|
||||
</part>
|
||||
<part id="part-5" href="howto/part-5.dita">
|
||||
<topicref id="key-creation" href="howto/part05/key-creation.dita"/>
|
||||
<topicref id="primary" href="howto/part05/primary-key.dita"/>
|
||||
<topicref id="subkeys" href="howto/part05/subkeys.dita"/>
|
||||
<topicref id="user-ids" href="howto/part05/user-ids.dita">
|
||||
<topicref id="add-uid" href="howto/part05/add-uid.dita"/>
|
||||
<topicref id="rev-uid" href="howto/part05/rev-uid.dita"/>
|
||||
</topicref>
|
||||
<topicref id="certify" href="howto/part05/certification.dita"/>
|
||||
</part>
|
||||
<part id="part-6" href="howto/part-6.dita">
|
||||
<topicref id="groups" href="howto/part06/group-lines.dita"/>
|
||||
</part>
|
||||
<backmatter>
|
||||
<mapref id="resources" href="resources.ditamap" processing-role="resource-only"/>
|
||||
</backmatter>
|
||||
</bookmap>
|
7
lang/python/docs/dita/gpgme-python.ditamap
Normal file
7
lang/python/docs/dita/gpgme-python.ditamap
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
|
||||
<map>
|
||||
<title>GPGME Python Bindings</title>
|
||||
<mapref id="howto-map" href="gpgme-python-howto.ditamap"/>
|
||||
<mapref id="resources" href="resources.ditamap" processing-role="resource-only"/>
|
||||
</map>
|
917
lang/python/docs/dita/gpgmePython.xpr
Normal file
917
lang/python/docs/dita/gpgmePython.xpr
Normal file
@ -0,0 +1,917 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="20.1">
|
||||
<meta>
|
||||
<filters directoryPatterns="" filePatterns="gpgmePython.xpr" positiveFilePatterns="" showHiddenFiles="false"/>
|
||||
<options>
|
||||
<serialized version="20.1" xml:space="preserve">
|
||||
<serializableOrderedMap>
|
||||
<entry>
|
||||
<String>scenario.associations</String>
|
||||
<scenarioAssociation-array>
|
||||
<scenarioAssociation>
|
||||
<field name="url">
|
||||
<String>gpgme-python.ditamap</String>
|
||||
</field>
|
||||
<field name="scenarioIds">
|
||||
<list>
|
||||
<String>DITA Map WebHelp - TS/HC - GPGME</String>
|
||||
</list>
|
||||
</field>
|
||||
<field name="scenarioTypes">
|
||||
<list>
|
||||
<String>DITAMAP</String>
|
||||
</list>
|
||||
</field>
|
||||
</scenarioAssociation>
|
||||
<scenarioAssociation>
|
||||
<field name="url">
|
||||
<String>gpgme-python-howto.ditamap</String>
|
||||
</field>
|
||||
<field name="scenarioIds">
|
||||
<list>
|
||||
<String>DITA Map WebHelp - TS/HC - GPGME</String>
|
||||
</list>
|
||||
</field>
|
||||
<field name="scenarioTypes">
|
||||
<list>
|
||||
<String>DITAMAP</String>
|
||||
</list>
|
||||
</field>
|
||||
</scenarioAssociation>
|
||||
</scenarioAssociation-array>
|
||||
</entry>
|
||||
<entry>
|
||||
<String>scenarios</String>
|
||||
<scenario-array>
|
||||
<ditaScenario>
|
||||
<field name="useXEP">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useAntennaHouse">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="baseDir">
|
||||
<String>${cfd}</String>
|
||||
</field>
|
||||
<field name="outputDir">
|
||||
<String>${cfd}/out/webhelp-${ddt}</String>
|
||||
</field>
|
||||
<field name="tempDir">
|
||||
<String>${cfd}/temp/webhelp-${ddt}</String>
|
||||
</field>
|
||||
<field name="transtype">
|
||||
<String>webhelp</String>
|
||||
</field>
|
||||
<field name="filters">
|
||||
<ditavalFilters>
|
||||
<field name="useDitavalFilePath">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useAppliedConditionSet">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="appliedConditionSet">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="ditavalFilePath">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="simpleFiltersList">
|
||||
<list/>
|
||||
</field>
|
||||
</ditavalFilters>
|
||||
</field>
|
||||
<field name="addOxygenJars">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="skinCssFile">
|
||||
<String>file:/usr/local/oXygenXML/custom/webhelp-skins/high-contrast-skin.css</String>
|
||||
</field>
|
||||
<field name="lastCustomSkinCssPath">
|
||||
<String>file:/usr/local/oXygenXML/custom/webhelp-skins/high-contrast-skin.css</String>
|
||||
</field>
|
||||
<field name="webhelpResponsiveTemplate">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="publishingTemplateDataPO">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="additionalAntArgs">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="buildTarget">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="buildFilePath">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="ditaParams">
|
||||
<list>
|
||||
<ditaParameter>
|
||||
<field name="name">
|
||||
<String>args.xhtml.classattr</String>
|
||||
</field>
|
||||
<field name="description">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="value">
|
||||
<String>yes</String>
|
||||
</field>
|
||||
<field name="defaultValue">
|
||||
<String>yes</String>
|
||||
</field>
|
||||
<field name="type">
|
||||
<Integer>4</Integer>
|
||||
</field>
|
||||
<field name="possibleValues">
|
||||
<String-array>
|
||||
<String>yes</String>
|
||||
<String>no</String>
|
||||
<null/>
|
||||
</String-array>
|
||||
</field>
|
||||
<field name="possibleValuesDescriptions">
|
||||
<String-array>
|
||||
<String></String>
|
||||
<String></String>
|
||||
</String-array>
|
||||
</field>
|
||||
</ditaParameter>
|
||||
<ditaParameter>
|
||||
<field name="name">
|
||||
<String>webhelp.footer.include</String>
|
||||
</field>
|
||||
<field name="description">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="value">
|
||||
<String>yes</String>
|
||||
</field>
|
||||
<field name="defaultValue">
|
||||
<String>yes</String>
|
||||
</field>
|
||||
<field name="type">
|
||||
<Integer>4</Integer>
|
||||
</field>
|
||||
<field name="possibleValues">
|
||||
<String-array>
|
||||
<String>yes</String>
|
||||
<String>no</String>
|
||||
<null/>
|
||||
</String-array>
|
||||
</field>
|
||||
<field name="possibleValuesDescriptions">
|
||||
<String-array>
|
||||
<String>If the "webhelp.footer.file" parameter has a value, the content of that file is used as footer. If "webhelp.footer.file" has no value, the default Oxygen footer is inserted in each Webhelp page.</String>
|
||||
<String>No footer is added to the Webhelp pages.</String>
|
||||
</String-array>
|
||||
</field>
|
||||
</ditaParameter>
|
||||
<ditaParameter>
|
||||
<field name="name">
|
||||
<String>webhelp.footer.file</String>
|
||||
</field>
|
||||
<field name="description">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="value">
|
||||
<String>/Users/ben/dev/hgit/mine/gnupg/dita/gpgme/python/gpgme-python-howto-footer.xhtml</String>
|
||||
</field>
|
||||
<field name="defaultValue">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="type">
|
||||
<Integer>2</Integer>
|
||||
</field>
|
||||
<field name="possibleValues">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="possibleValuesDescriptions">
|
||||
<null/>
|
||||
</field>
|
||||
</ditaParameter>
|
||||
<ditaParameter>
|
||||
<field name="name">
|
||||
<String>webhelp.copyright</String>
|
||||
</field>
|
||||
<field name="description">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="value">
|
||||
<String>Copyright © Benjamin D. McGinnes, 2018</String>
|
||||
</field>
|
||||
<field name="defaultValue">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="type">
|
||||
<Integer>0</Integer>
|
||||
</field>
|
||||
<field name="possibleValues">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="possibleValuesDescriptions">
|
||||
<null/>
|
||||
</field>
|
||||
</ditaParameter>
|
||||
</list>
|
||||
</field>
|
||||
<field name="jvmArgs">
|
||||
<String>-Xmx384m</String>
|
||||
</field>
|
||||
<field name="useCustomJavaHome">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="customJavaHomeDir">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="useCustomANTHome">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="customANTHomeDir">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="workingDir">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="showConsoleAlways">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="advancedOptionsMap">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="name">
|
||||
<String>DITA Map WebHelp - TS/HC - GPGME</String>
|
||||
</field>
|
||||
<field name="baseURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="footerURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="fOPMethod">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="fOProcessorName">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="headerURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="inputXSLURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="inputXMLURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="defaultScenario">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="isFOPPerforming">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="type">
|
||||
<String>DITAMAP</String>
|
||||
</field>
|
||||
<field name="saveAs">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="openInBrowser">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="outputFile">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="outputResource">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="openOtherLocationInBrowser">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="locationToOpenInBrowserURL">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="openInEditor">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInHTMLPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInXMLPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInSVGPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInResultSetPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useXSLTInput">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="xsltParams">
|
||||
<list/>
|
||||
</field>
|
||||
<field name="cascadingStylesheets">
|
||||
<String-array/>
|
||||
</field>
|
||||
<field name="xslTransformer">
|
||||
<String>DITA-OT</String>
|
||||
</field>
|
||||
<field name="extensionURLs">
|
||||
<String-array/>
|
||||
</field>
|
||||
</ditaScenario>
|
||||
<ditaScenario>
|
||||
<field name="useXEP">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useAntennaHouse">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="baseDir">
|
||||
<String>${cfd}</String>
|
||||
</field>
|
||||
<field name="outputDir">
|
||||
<String>${cfd}/out/html5-${ddt}</String>
|
||||
</field>
|
||||
<field name="tempDir">
|
||||
<String>${cfd}/temp/html5-${ddt}</String>
|
||||
</field>
|
||||
<field name="transtype">
|
||||
<String>html5</String>
|
||||
</field>
|
||||
<field name="filters">
|
||||
<ditavalFilters>
|
||||
<field name="useDitavalFilePath">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useAppliedConditionSet">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="appliedConditionSet">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="ditavalFilePath">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="simpleFiltersList">
|
||||
<list/>
|
||||
</field>
|
||||
</ditavalFilters>
|
||||
</field>
|
||||
<field name="addOxygenJars">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="skinCssFile">
|
||||
<String>file:/usr/local/oXygenXML/custom/webhelp-skins/high-contrast-skin.css</String>
|
||||
</field>
|
||||
<field name="lastCustomSkinCssPath">
|
||||
<String>file:/usr/local/oXygenXML/custom/webhelp-skins/high-contrast-skin.css</String>
|
||||
</field>
|
||||
<field name="webhelpResponsiveTemplate">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="publishingTemplateDataPO">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="additionalAntArgs">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="buildTarget">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="buildFilePath">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="ditaParams">
|
||||
<list/>
|
||||
</field>
|
||||
<field name="jvmArgs">
|
||||
<String>-Xmx384m</String>
|
||||
</field>
|
||||
<field name="useCustomJavaHome">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="customJavaHomeDir">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="useCustomANTHome">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="customANTHomeDir">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="workingDir">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="showConsoleAlways">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="advancedOptionsMap">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="name">
|
||||
<String>gpgme-python (HTML5)</String>
|
||||
</field>
|
||||
<field name="baseURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="footerURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="fOPMethod">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="fOProcessorName">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="headerURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="inputXSLURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="inputXMLURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="defaultScenario">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="isFOPPerforming">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="type">
|
||||
<String>DITAMAP</String>
|
||||
</field>
|
||||
<field name="saveAs">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="openInBrowser">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="outputFile">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="outputResource">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="openOtherLocationInBrowser">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="locationToOpenInBrowserURL">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="openInEditor">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInHTMLPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInXMLPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInSVGPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInResultSetPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useXSLTInput">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="xsltParams">
|
||||
<list/>
|
||||
</field>
|
||||
<field name="cascadingStylesheets">
|
||||
<String-array/>
|
||||
</field>
|
||||
<field name="xslTransformer">
|
||||
<String>DITA-OT</String>
|
||||
</field>
|
||||
<field name="extensionURLs">
|
||||
<String-array/>
|
||||
</field>
|
||||
</ditaScenario>
|
||||
<ditaScenario>
|
||||
<field name="useXEP">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useAntennaHouse">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="baseDir">
|
||||
<String>${cfd}</String>
|
||||
</field>
|
||||
<field name="outputDir">
|
||||
<String>${cfd}/out/html5</String>
|
||||
</field>
|
||||
<field name="tempDir">
|
||||
<String>${cfd}/temp/html5</String>
|
||||
</field>
|
||||
<field name="transtype">
|
||||
<String>html5</String>
|
||||
</field>
|
||||
<field name="filters">
|
||||
<ditavalFilters>
|
||||
<field name="useDitavalFilePath">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useAppliedConditionSet">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="appliedConditionSet">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="ditavalFilePath">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="simpleFiltersList">
|
||||
<list/>
|
||||
</field>
|
||||
</ditavalFilters>
|
||||
</field>
|
||||
<field name="addOxygenJars">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="skinCssFile">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="lastCustomSkinCssPath">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="webhelpResponsiveTemplate">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="publishingTemplateDataPO">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="additionalAntArgs">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="buildTarget">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="buildFilePath">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="ditaParams">
|
||||
<list/>
|
||||
</field>
|
||||
<field name="jvmArgs">
|
||||
<String>-Xmx384m</String>
|
||||
</field>
|
||||
<field name="useCustomJavaHome">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="customJavaHomeDir">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="useCustomANTHome">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="customANTHomeDir">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="workingDir">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="showConsoleAlways">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="advancedOptionsMap">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="name">
|
||||
<String>gpgme-python-howto (HTML5)</String>
|
||||
</field>
|
||||
<field name="baseURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="footerURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="fOPMethod">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="fOProcessorName">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="headerURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="inputXSLURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="inputXMLURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="defaultScenario">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="isFOPPerforming">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="type">
|
||||
<String>DITAMAP</String>
|
||||
</field>
|
||||
<field name="saveAs">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="openInBrowser">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="outputFile">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="outputResource">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="openOtherLocationInBrowser">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="locationToOpenInBrowserURL">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="openInEditor">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInHTMLPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInXMLPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInSVGPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInResultSetPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useXSLTInput">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="xsltParams">
|
||||
<list/>
|
||||
</field>
|
||||
<field name="cascadingStylesheets">
|
||||
<String-array/>
|
||||
</field>
|
||||
<field name="xslTransformer">
|
||||
<String>DITA-OT</String>
|
||||
</field>
|
||||
<field name="extensionURLs">
|
||||
<String-array/>
|
||||
</field>
|
||||
</ditaScenario>
|
||||
<ditaScenario>
|
||||
<field name="useXEP">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useAntennaHouse">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="baseDir">
|
||||
<String>${cfd}</String>
|
||||
</field>
|
||||
<field name="outputDir">
|
||||
<String>${cfd}/out/webhelp-responsive-${ddt}</String>
|
||||
</field>
|
||||
<field name="tempDir">
|
||||
<String>${cfd}/temp/webhelp-responsive-${ddt}</String>
|
||||
</field>
|
||||
<field name="transtype">
|
||||
<String>webhelp-responsive</String>
|
||||
</field>
|
||||
<field name="filters">
|
||||
<ditavalFilters>
|
||||
<field name="useDitavalFilePath">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useAppliedConditionSet">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="appliedConditionSet">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="ditavalFilePath">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="simpleFiltersList">
|
||||
<list/>
|
||||
</field>
|
||||
</ditavalFilters>
|
||||
</field>
|
||||
<field name="addOxygenJars">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="skinCssFile">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="lastCustomSkinCssPath">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="webhelpResponsiveTemplate">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="publishingTemplateDataPO">
|
||||
<publishingTemplate>
|
||||
<field name="templateRoot">
|
||||
<String>${configured.ditaot.dir}/plugins/com.oxygenxml.webhelp.responsive/templates/oxygen</String>
|
||||
</field>
|
||||
<field name="descriptorRelativePath">
|
||||
<String>oxygen-tiles.opt</String>
|
||||
</field>
|
||||
<field name="isCustomTemplate">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
</publishingTemplate>
|
||||
</field>
|
||||
<field name="additionalAntArgs">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="buildTarget">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="buildFilePath">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="ditaParams">
|
||||
<list>
|
||||
<ditaParameter>
|
||||
<field name="name">
|
||||
<String>force-unique</String>
|
||||
</field>
|
||||
<field name="description">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="value">
|
||||
<String>true</String>
|
||||
</field>
|
||||
<field name="defaultValue">
|
||||
<String>false</String>
|
||||
</field>
|
||||
<field name="type">
|
||||
<Integer>4</Integer>
|
||||
</field>
|
||||
<field name="possibleValues">
|
||||
<String-array>
|
||||
<String>true</String>
|
||||
<String>false</String>
|
||||
<null/>
|
||||
</String-array>
|
||||
</field>
|
||||
<field name="possibleValuesDescriptions">
|
||||
<String-array>
|
||||
<String></String>
|
||||
<String></String>
|
||||
</String-array>
|
||||
</field>
|
||||
</ditaParameter>
|
||||
<ditaParameter>
|
||||
<field name="name">
|
||||
<String>args.xhtml.classattr</String>
|
||||
</field>
|
||||
<field name="description">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="value">
|
||||
<String>yes</String>
|
||||
</field>
|
||||
<field name="defaultValue">
|
||||
<String>yes</String>
|
||||
</field>
|
||||
<field name="type">
|
||||
<Integer>4</Integer>
|
||||
</field>
|
||||
<field name="possibleValues">
|
||||
<String-array>
|
||||
<String>yes</String>
|
||||
<String>no</String>
|
||||
<null/>
|
||||
</String-array>
|
||||
</field>
|
||||
<field name="possibleValuesDescriptions">
|
||||
<String-array>
|
||||
<String></String>
|
||||
<String></String>
|
||||
</String-array>
|
||||
</field>
|
||||
</ditaParameter>
|
||||
</list>
|
||||
</field>
|
||||
<field name="jvmArgs">
|
||||
<String>-Xmx384m</String>
|
||||
</field>
|
||||
<field name="useCustomJavaHome">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="customJavaHomeDir">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="useCustomANTHome">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="customANTHomeDir">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="workingDir">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="showConsoleAlways">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="advancedOptionsMap">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="name">
|
||||
<String>gpgme-python-howto (WebHelp Responsive)</String>
|
||||
</field>
|
||||
<field name="baseURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="footerURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="fOPMethod">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="fOProcessorName">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="headerURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="inputXSLURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="inputXMLURL">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="defaultScenario">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="isFOPPerforming">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="type">
|
||||
<String>DITAMAP</String>
|
||||
</field>
|
||||
<field name="saveAs">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="openInBrowser">
|
||||
<Boolean>true</Boolean>
|
||||
</field>
|
||||
<field name="outputFile">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="outputResource">
|
||||
<null/>
|
||||
</field>
|
||||
<field name="openOtherLocationInBrowser">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="locationToOpenInBrowserURL">
|
||||
<String></String>
|
||||
</field>
|
||||
<field name="openInEditor">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInHTMLPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInXMLPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInSVGPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="showInResultSetPane">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="useXSLTInput">
|
||||
<Boolean>false</Boolean>
|
||||
</field>
|
||||
<field name="xsltParams">
|
||||
<list/>
|
||||
</field>
|
||||
<field name="cascadingStylesheets">
|
||||
<String-array/>
|
||||
</field>
|
||||
<field name="xslTransformer">
|
||||
<String>DITA-OT</String>
|
||||
</field>
|
||||
<field name="extensionURLs">
|
||||
<String-array/>
|
||||
</field>
|
||||
</ditaScenario>
|
||||
</scenario-array>
|
||||
</entry>
|
||||
</serializableOrderedMap>
|
||||
</serialized>
|
||||
</options>
|
||||
</meta>
|
||||
<projectTree name="gpgmePython.xpr">
|
||||
<folder path="."/>
|
||||
</projectTree>
|
||||
</project>
|
10
lang/python/docs/dita/howto/part-1.dita
Normal file
10
lang/python/docs/dita/howto/part-1.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_syw_3qx_5db">
|
||||
<title>Introducing the Python Bindings</title>
|
||||
<body>
|
||||
<p></p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
10
lang/python/docs/dita/howto/part-2.dita
Normal file
10
lang/python/docs/dita/howto/part-2.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_y52_zwx_5db">
|
||||
<title>Preparation and Setting Up</title>
|
||||
<body>
|
||||
<p></p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
10
lang/python/docs/dita/howto/part-3.dita
Normal file
10
lang/python/docs/dita/howto/part-3.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_s5w_23y_5db">
|
||||
<title>Working With Keys</title>
|
||||
<body>
|
||||
<p></p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
10
lang/python/docs/dita/howto/part-4.dita
Normal file
10
lang/python/docs/dita/howto/part-4.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_dz3_mpy_5db">
|
||||
<title>Cryptographic Functions</title>
|
||||
<body>
|
||||
<p></p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
10
lang/python/docs/dita/howto/part-5.dita
Normal file
10
lang/python/docs/dita/howto/part-5.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_akd_rwz_5db">
|
||||
<title>Generating Keys</title>
|
||||
<body>
|
||||
<p></p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
10
lang/python/docs/dita/howto/part-6.dita
Normal file
10
lang/python/docs/dita/howto/part-6.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_bdk_vwz_5db">
|
||||
<title>Miscellaneous Work-arounds</title>
|
||||
<body>
|
||||
<p></p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
30
lang/python/docs/dita/howto/part01/docs-source.dita
Normal file
30
lang/python/docs/dita/howto/part01/docs-source.dita
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_nb3_hrx_5db">
|
||||
<title>Documentation Source Files</title>
|
||||
<body>
|
||||
<p>Unlike all other documentation in the <xref href="https://gnupg.org" format="html"
|
||||
scope="external">GnuPG Project</xref>, including the initial version of this HOWTO, this
|
||||
version was <i>not</i> written in Emacs Org-Mode. Nor was it written in LaTeX, Texinfo or
|
||||
even directly in HTML. Instead it was written using the Darwin Information Typing
|
||||
Architecture (DITA) XML.</p>
|
||||
<p>This was done for two main reasons:</p>
|
||||
<p>
|
||||
<ol id="ol_k3b_wrx_5db">
|
||||
<li>A <xref href="https://dev.gnupg.org/T3977" format="html" scope="external">bug</xref>
|
||||
in either Org-Mode or Babel prevented the more complex examples included in the HOWTO
|
||||
from displaying correctly while also retaining syntax highlighting.</li>
|
||||
<li>To demonstrate some of the advantages of DITA XML over existing documentation
|
||||
production software used in the project (particularly Texinfo and LaTeX).</li>
|
||||
</ol>
|
||||
</p>
|
||||
<p>The XML format definitely supports displaying all the more complex Python code correctly
|
||||
with syntax highlighting, as well as being designed to produce standards compliant print and
|
||||
HTML output. Whereas currently the existing tools utilised by the GnuPG Project can't
|
||||
display the example code in a way which would actually pass the project's own git commit
|
||||
ruleset.</p>
|
||||
<p> </p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
11
lang/python/docs/dita/howto/part01/examples.dita
Normal file
11
lang/python/docs/dita/howto/part01/examples.dita
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_bv2_qqx_5db">
|
||||
<title>Examples</title>
|
||||
<body>
|
||||
<p>All of the examples found in this document can be found as Python 3 scripts in the
|
||||
<filepath>lang/python/examples/howto</filepath> directory.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
11
lang/python/docs/dita/howto/part01/introduction.dita
Normal file
11
lang/python/docs/dita/howto/part01/introduction.dita
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_ucm_3mx_5db">
|
||||
<title>Introduction</title>
|
||||
<body>
|
||||
<p>This document provides basic instruction in how to use the GPGME Python bindings to
|
||||
programmatically leverage the GPGME library.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
22
lang/python/docs/dita/howto/part01/python2-vs-python3.dita
Normal file
22
lang/python/docs/dita/howto/part01/python2-vs-python3.dita
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_j1r_qmx_5db">
|
||||
<title>Python 2 vs. Python 3</title>
|
||||
<body>
|
||||
<p>Though the GPGME Python bindings themselves provide support for both Python 2 and 3,
|
||||
the focus is unequivocally on Python 3 and specifically from Python 3.4 and above. As a
|
||||
consequence all the examples and instructions in this guide use Python 3 code.</p>
|
||||
<p>Much of it will work with Python 2, but much of it also deals with Python 3 byte literals,
|
||||
particularly when reading and writing data. Developers concentrating on Python 2.7, and
|
||||
possibly even 2.6, will need to make the appropriate modifications to support the older
|
||||
string and unicode types as opposed to bytes.</p>
|
||||
<p>There are multiple reasons for concentrating on Python 3; some of which relate to the
|
||||
immediate integration of these bindings, some of which relate to longer term plans for both
|
||||
GPGME and the python bindings and some of which relate to the impending EOL period for
|
||||
Python 2.7. Essentially, though, there is little value in tying the bindings to a version of
|
||||
the language which is a dead end and the advantages offered by Python 3 over Python 2 make
|
||||
handling the data types with which GPGME deals considerably easier.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
17
lang/python/docs/dita/howto/part02/c-api.dita
Normal file
17
lang/python/docs/dita/howto/part02/c-api.dita
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_jrb_pxx_5db">
|
||||
<title>A C API</title>
|
||||
<body>
|
||||
<p>Unlike many modern APIs with which programmers will be more familiar with these days,
|
||||
the GPGME API is a C API. The API is intended for use by C coders who would be able to
|
||||
access its features by including the =gpgme.h= header file with their own C source code and
|
||||
then access its functions just as they would any other C headers.</p>
|
||||
<p>This is a very effective method of gaining complete access to the API and in the most
|
||||
efficient manner possible. It does, however, have the drawback that it cannot be directly
|
||||
used by other languages without some means of providing an interface to those languages.
|
||||
This is where the need for bindings in various languages stems.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
21
lang/python/docs/dita/howto/part02/context.dita
Normal file
21
lang/python/docs/dita/howto/part02/context.dita
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_bpb_why_5db">
|
||||
<title>Context</title>
|
||||
<body>
|
||||
<p>One of the reasons which prevents this API from being RESTful is that most operations
|
||||
require more than one instruction to the API to perform the task. Sure, there are certain
|
||||
functions which can be performed simultaneously, particularly if the result known or
|
||||
strongly anticipated (e.g. selecting and encrypting to a key known to be in the public
|
||||
keybox).</p>
|
||||
<p>There are many more, however, which cannot be manipulated so readily: they must be
|
||||
performed in a specific sequence and the result of one operation has a direct bearing on the
|
||||
outcome of subsequent operations. Not merely by generating an error either.</p>
|
||||
<p>When dealing with this type of persistent state on the web, full of both the RESTful and
|
||||
REST-like, it's most commonly referred to as a session. In GPGME, however, it is called a
|
||||
context and every operation type has one.</p>
|
||||
<p/>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_ecj_yyx_5db">
|
||||
<title>Difference between the Python bindings and other GnuPG Python packages</title>
|
||||
<body>
|
||||
<p>There have been numerous attempts to add GnuPG support to Python over the years. Some
|
||||
of the most well known are listed here, along with what differentiates them.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
12
lang/python/docs/dita/howto/part02/fundamentals.dita
Normal file
12
lang/python/docs/dita/howto/part02/fundamentals.dita
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_xsp_ygy_5db">
|
||||
<title>Fundamentals</title>
|
||||
<body>
|
||||
<p>Before we can get to the fun stuff, there are a few matters regarding GPGME's design
|
||||
which hold true whether you're dealing with the C code directly or these Python
|
||||
bindings.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
10
lang/python/docs/dita/howto/part02/gpgme-concepts.dita
Normal file
10
lang/python/docs/dita/howto/part02/gpgme-concepts.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_zm1_lxx_5db">
|
||||
<title>GPGME Concepts</title>
|
||||
<body>
|
||||
<p/>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
10
lang/python/docs/dita/howto/part02/installation.dita
Normal file
10
lang/python/docs/dita/howto/part02/installation.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_isl_32y_5db">
|
||||
<title>GPGME Python bindings installation</title>
|
||||
<body>
|
||||
<p></p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
23
lang/python/docs/dita/howto/part02/installing.dita
Normal file
23
lang/python/docs/dita/howto/part02/installing.dita
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_ivh_zfy_5db">
|
||||
<title>Installing</title>
|
||||
<body>
|
||||
<p>Installing the Python bindings is effectively achieved by compiling and installing GPGME
|
||||
itself.</p>
|
||||
<p>Once SWIG is installed with Python and all the dependencies for GPGME are installed you
|
||||
only need to confirm that the version(s) of Python you want the bindings installed for are
|
||||
in your <codeph>$PATH</codeph>.</p>
|
||||
<p>By default GPGME will attempt to install the bindings for the most recent or highest
|
||||
version number of Python 2 and Python 3 it detects in <codeph>$PATH</codeph>. It
|
||||
specifically checks for the <cmdname>python</cmdname> and <cmdname>python3</cmdname>
|
||||
executables first and then checks for specific version numbers.</p>
|
||||
<p>For Python 2 it checks for these executables in this order: <cmdname>python</cmdname>,
|
||||
<cmdname>python2</cmdname> and <cmdname>python2.7</cmdname>.</p>
|
||||
<p>For Python 3 it checks for these executables in this order: <cmdname>python3</cmdname>,
|
||||
<cmdname>python3.6</cmdname>, <cmdname>python3.5</cmdname>, <cmdname>python3.4</cmdname>
|
||||
and <cmdname>python3.7</cmdname>.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
20
lang/python/docs/dita/howto/part02/isis-gnupg.dita
Normal file
20
lang/python/docs/dita/howto/part02/isis-gnupg.dita
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_ob2_yzx_5db">
|
||||
<title>The gnupg package created and maintained by Isis Lovecruft</title>
|
||||
<body>
|
||||
<p>In 2015 Isis Lovecruft from the Tor Project forked and then re-implemented the
|
||||
python-gnupg package as just gnupg. This new package also relied on
|
||||
<codeph>subprocess</codeph> to call the <cmdname>gpg</cmdname> or <cmdname>gpg2</cmdname>
|
||||
binaries, but did so somewhat more securely.</p>
|
||||
<p>The naming and version numbering selected for this package, however, resulted in conflicts
|
||||
with the original python-gnupg and since its functions were called in a different manner to
|
||||
python-gnupg, the release of this package also resulted in a great deal of consternation
|
||||
when people installed what they thought was an upgrade that subsequently broke the code
|
||||
relying on it.</p>
|
||||
<p>The gnupg package is available under the GNU General Public License version 3.0 (or any
|
||||
later version).</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
19
lang/python/docs/dita/howto/part02/no-pypi.dita
Normal file
19
lang/python/docs/dita/howto/part02/no-pypi.dita
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_mss_p2y_5db">
|
||||
<title>No PyPI</title>
|
||||
<body>
|
||||
<p>Most third-party Python packages and modules are available and distributed through
|
||||
the Python Package Installer, known as PyPI.</p>
|
||||
<p>Due to the nature of what these bindings are and how they work, it is infeasible to install
|
||||
the GPGME Python bindings in the same way.</p>
|
||||
<p>This is because the bindings use SWIG to dynamically generate C bindings against
|
||||
<codeph>gpgme.h</codeph> and <codeph>gpgme.h</codeph> is generated from
|
||||
<codeph>gpgme.h.in</codeph> at compile time when GPGME is built from source. Thus to
|
||||
include a package in PyPI which actually built correctly would require either statically
|
||||
built libraries for every architecture bundled with it or a full implementation of C for
|
||||
each architecture.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
20
lang/python/docs/dita/howto/part02/no-rest.dita
Normal file
20
lang/python/docs/dita/howto/part02/no-rest.dita
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_wmg_2hy_5db">
|
||||
<title>No REST</title>
|
||||
<body>
|
||||
<p>The first part of which is or will be fairly blatantly obvious upon viewing the first
|
||||
example, but it's worth reiterating anyway. That being that this API is <b><i>not</i></b> a
|
||||
REST API. Nor indeed could it ever be one.</p>
|
||||
<p>Most, if not all, Python programmers (and not just Python programmers) know how easy it is
|
||||
to work with a RESTful API. In fact they've become so popular that many other APIs attempt
|
||||
to emulate REST-like behaviour as much as they are able. Right down to the use of JSON
|
||||
formatted output to facilitate the use of their API without having to retrain
|
||||
developers.</p>
|
||||
<p>This API does not do that. It would not be able to do that and also provide access to the
|
||||
entire C API on which it's built. It does, however, provide a very pythonic interface on top
|
||||
of the direct bindings and it's this pythonic layer with which this HOWTO deals with.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
25
lang/python/docs/dita/howto/part02/pyme.dita
Normal file
25
lang/python/docs/dita/howto/part02/pyme.dita
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_oy4_zcy_5db">
|
||||
<title>The PyME package maintained by Martin Albrecht</title>
|
||||
<body>
|
||||
<p>This package is the origin of these bindings, though they are somewhat different now. For
|
||||
details of when and how the PyME package was folded back into GPGME itself see the
|
||||
<cite>Short History</cite> document<fn><codeph>Short_History.org</codeph> and/or
|
||||
<codeph>Short_History.html</codeph>.</fn> in the Python bindings <codeph>docs/</codeph>
|
||||
directory.<fn>The <filepath>lang/python/docs/</filepath> directory in the GPGME
|
||||
source.</fn></p>
|
||||
<p>The PyME package was first released in 2002 and was also the first attempt to implement a
|
||||
low level binding to GPGME. In doing so it provided access to considerably more
|
||||
functionality than either the <codeph>python-gnupg</codeph> or <codeph>gnupg</codeph>
|
||||
packages.</p>
|
||||
<p>The PyME package is only available for Python 2.6 and 2.7.</p>
|
||||
<p>Porting the PyME package to Python 3.4 in 2015 is what resulted in it being folded into the
|
||||
GPGME project and the current bindings are the end result of that effort.</p>
|
||||
<p>The PyME package is available under the same dual licensing as GPGME itself: the GNU
|
||||
General Public License version 2.0 (or any later version) and the GNU Lesser General Public
|
||||
License version 2.1 (or any later version).</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
16
lang/python/docs/dita/howto/part02/python-bindings.dita
Normal file
16
lang/python/docs/dita/howto/part02/python-bindings.dita
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_g4z_wxx_5db">
|
||||
<title>Python Bindings</title>
|
||||
<body>
|
||||
<p>The Python bindings for GPGME provide a higher level means of accessing the complete
|
||||
feature set of GPGME itself. It also provides a more pythonic means of calling these API
|
||||
functions.</p>
|
||||
<p>The bindings are generated dynamically with SWIG and the copy of <codeph>gpgme.h</codeph>
|
||||
generated when GPGME is compiled.</p>
|
||||
<p>This means that a version of the Python bindings is fundamentally tied to the exact same
|
||||
version of GPGME used to generate that copy of <codeph>gpgme.h</codeph>.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
22
lang/python/docs/dita/howto/part02/python-gnupg.dita
Normal file
22
lang/python/docs/dita/howto/part02/python-gnupg.dita
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_llw_kzx_5db">
|
||||
<title>The python-gnupg package maintained by Vinay Sajip</title>
|
||||
<body>
|
||||
<p>This is arguably the most popular means of integrating GPG with Python. The package
|
||||
utilises the <codeph>subprocess</codeph> module to implement wrappers for the
|
||||
<cmdname>gpg</cmdname> and <cmdname>gpg2</cmdname> executables normally invoked on the command
|
||||
line (<cmdname>gpg.exe</cmdname> and <cmdname>gpg2.exe</cmdname> on Windows).</p>
|
||||
<p>The popularity of this package stemmed from its ease of use and capability in providing the
|
||||
most commonly required features.</p>
|
||||
<p>Unfortunately it has been beset by a number of security issues in the past; most of which
|
||||
stemmed from using unsafe methods of accessing the command line via the
|
||||
<codeph>subprocess</codeph> calls. While some effort has been made over the last two to
|
||||
three years (as of 2018) to mitigate this, particularly by no longer providing shell access
|
||||
through those subprocess calls, the wrapper is still somewhat limited in the scope of its
|
||||
GnuPG features coverage.</p>
|
||||
<p>The python-gnupg package is available under the MIT license.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
20
lang/python/docs/dita/howto/part02/requirements.dita
Normal file
20
lang/python/docs/dita/howto/part02/requirements.dita
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_zqn_nfy_5db">
|
||||
<title>Requirements</title>
|
||||
<body>
|
||||
<p>The GPGME Python bindings only have three requirements:</p>
|
||||
<p>
|
||||
<ol id="ol_rbw_qfy_5db">
|
||||
<li>A suitable version of Python 2 or Python 3. With Python 2 that means Python 2.7 and
|
||||
with Python 3 that means Python 3.4 or higher.</li>
|
||||
<li>SWIG.</li>
|
||||
<li>GPGME itself. Which also means that all of GPGME's dependencies must be installed
|
||||
too.</li>
|
||||
</ol>
|
||||
</p>
|
||||
<p/>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
120
lang/python/docs/dita/howto/part03/exporting-pubkeys.dita
Normal file
120
lang/python/docs/dita/howto/part03/exporting-pubkeys.dita
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="exporting-pubkeys">
|
||||
<title>Exporting Public Keys</title>
|
||||
<body>
|
||||
<p>There are two methods of exporting public keys, both of which are very similar to the
|
||||
other. The default method, <codeph>key_export()</codeph>, will export a public key or keys
|
||||
matching a specified pattern as normal. The alternative, the
|
||||
<codeph>key_export_minimal()</codeph> method, will do the same thing except producing a
|
||||
minimised output with extra signatures and third party signatures or certifications
|
||||
removed.</p>
|
||||
<p>
|
||||
<codeblock id="export-pubkey-01" outputclass="language-python">import gpg
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
print("""
|
||||
This script exports one or more public keys.
|
||||
""")
|
||||
|
||||
c = gpg.Context(armor=True)
|
||||
|
||||
if len(sys.argv) >= 4:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = sys.argv[2]
|
||||
homedir = sys.argv[3]
|
||||
elif len(sys.argv) == 3:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = sys.argv[2]
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
elif len(sys.argv) == 2:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
else:
|
||||
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
|
||||
if homedir.startswith("~"):
|
||||
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||
c.home_dir = os.path.expanduser(homedir)
|
||||
else:
|
||||
pass
|
||||
elif os.path.exists(homedir) is True:
|
||||
c.home_dir = homedir
|
||||
else:
|
||||
pass
|
||||
|
||||
try:
|
||||
result = c.key_export(pattern=logrus)
|
||||
except:
|
||||
result = c.key_export(pattern=None)
|
||||
|
||||
if result is not None:
|
||||
with open(keyfile, "wb") as f:
|
||||
f.write(result)
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>It is important to note that the <codeph>result</codeph> will only return
|
||||
<codeph>None</codeph> when a pattern has been entered for <varname>logrus</varname>, but
|
||||
it has not matched any keys. When the search pattern itself is set to <codeph>None</codeph>
|
||||
this triggers the exporting of the entire public keybox.</p>
|
||||
<p>
|
||||
<codeblock id="export-pubkey-02" outputclass="language-python">import gpg
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
print("""
|
||||
This script exports one or more public keys in minimised form.
|
||||
""")
|
||||
|
||||
c = gpg.Context(armor=True)
|
||||
|
||||
if len(sys.argv) >= 4:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = sys.argv[2]
|
||||
homedir = sys.argv[3]
|
||||
elif len(sys.argv) == 3:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = sys.argv[2]
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
elif len(sys.argv) == 2:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
else:
|
||||
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||
logrus = input("Enter the UID matching the key(s) to export: ")
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
|
||||
if homedir.startswith("~"):
|
||||
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||
c.home_dir = os.path.expanduser(homedir)
|
||||
else:
|
||||
pass
|
||||
elif os.path.exists(homedir) is True:
|
||||
c.home_dir = homedir
|
||||
else:
|
||||
pass
|
||||
|
||||
try:
|
||||
result = c.key_export_minimal(pattern=logrus)
|
||||
except:
|
||||
result = c.key_export_minimal(pattern=None)
|
||||
|
||||
if result is not None:
|
||||
with open(keyfile, "wb") as f:
|
||||
f.write(result)
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p/>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
161
lang/python/docs/dita/howto/part03/exporting-seckeys.dita
Normal file
161
lang/python/docs/dita/howto/part03/exporting-seckeys.dita
Normal file
@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="exporting-seckeys">
|
||||
<title>Exporting Secret Keys</title>
|
||||
<body>
|
||||
<p>Exporting secret keys is, functionally, very similar to exporting public keys; save for the
|
||||
invocation of <cmdname>pinentry</cmdname> via <cmdname>gpg-agent</cmdname> in order to
|
||||
securely enter the key's passphrase and authorise the export.</p>
|
||||
<p>The following example exports the secret key to a file which is then set with the same
|
||||
permissions as the output files created by the command line secret key export options.</p>
|
||||
<p>
|
||||
<codeblock id="export-seckey-01" outputclass="language-python">import gpg
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
print("""
|
||||
This script exports one or more secret keys.
|
||||
|
||||
The gpg-agent and pinentry are invoked to authorise the export.
|
||||
""")
|
||||
|
||||
c = gpg.Context(armor=True)
|
||||
|
||||
if len(sys.argv) >= 4:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = sys.argv[2]
|
||||
homedir = sys.argv[3]
|
||||
elif len(sys.argv) == 3:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = sys.argv[2]
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
elif len(sys.argv) == 2:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
else:
|
||||
keyfile = input("Enter the path and filename to save the secret key to: ")
|
||||
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
|
||||
if homedir.startswith("~"):
|
||||
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||
c.home_dir = os.path.expanduser(homedir)
|
||||
else:
|
||||
pass
|
||||
elif os.path.exists(homedir) is True:
|
||||
c.home_dir = homedir
|
||||
else:
|
||||
pass
|
||||
|
||||
try:
|
||||
result = c.key_export_secret(pattern=logrus)
|
||||
except:
|
||||
result = c.key_export_secret(pattern=None)
|
||||
|
||||
if result is not None:
|
||||
with open(keyfile, "wb") as f:
|
||||
f.write(result)
|
||||
os.chmod(keyfile, 0o600)
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>Alternatively the approach of the following script can be used. This longer example saves
|
||||
the exported secret key(s) in files in the GnuPG home directory, in addition to setting the
|
||||
file permissions as only readable and writable by the user. It also exports the secret
|
||||
key(s) twice in order to output both GPG binary (<codeph>.gpg</codeph>) and ASCII armoured
|
||||
(<codeph>.asc</codeph>) files.</p>
|
||||
<p>
|
||||
<codeblock id="export-seckey-02" outputclass="language-python">import gpg
|
||||
import os
|
||||
import os.path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
print("""
|
||||
This script exports one or more secret keys as both ASCII armored and binary
|
||||
file formats, saved in files within the user's GPG home directory.
|
||||
|
||||
The gpg-agent and pinentry are invoked to authorise the export.
|
||||
""")
|
||||
|
||||
if sys.platform == "win32":
|
||||
gpgconfcmd = "gpgconf.exe --list-dirs homedir"
|
||||
else:
|
||||
gpgconfcmd = "gpgconf --list-dirs homedir"
|
||||
|
||||
a = gpg.Context(armor=True)
|
||||
b = gpg.Context()
|
||||
c = gpg.Context()
|
||||
|
||||
if len(sys.argv) >= 4:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = sys.argv[2]
|
||||
homedir = sys.argv[3]
|
||||
elif len(sys.argv) == 3:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = sys.argv[2]
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
elif len(sys.argv) == 2:
|
||||
keyfile = sys.argv[1]
|
||||
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
else:
|
||||
keyfile = input("Enter the filename to save the secret key to: ")
|
||||
logrus = input("Enter the UID matching the secret key(s) to export: ")
|
||||
homedir = input("Enter the GPG configuration directory path (optional): ")
|
||||
|
||||
if homedir.startswith("~"):
|
||||
if os.path.exists(os.path.expanduser(homedir)) is True:
|
||||
c.home_dir = os.path.expanduser(homedir)
|
||||
else:
|
||||
pass
|
||||
elif os.path.exists(homedir) is True:
|
||||
c.home_dir = homedir
|
||||
else:
|
||||
pass
|
||||
|
||||
if c.home_dir is not None:
|
||||
if c.home_dir.endswith("/"):
|
||||
gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile)
|
||||
ascfile = "{0}{1}.asc".format(c.home_dir, keyfile)
|
||||
else:
|
||||
gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile)
|
||||
ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile)
|
||||
else:
|
||||
if os.path.exists(os.environ["GNUPGHOME"]) is True:
|
||||
hd = os.environ["GNUPGHOME"]
|
||||
else:
|
||||
hd = subprocess.getoutput(gpgconfcmd)
|
||||
gpgfile = "{0}/{1}.gpg".format(hd, keyfile)
|
||||
ascfile = "{0}/{1}.asc".format(hd, keyfile)
|
||||
|
||||
try:
|
||||
a_result = a.key_export_secret(pattern=logrus)
|
||||
b_result = b.key_export_secret(pattern=logrus)
|
||||
except:
|
||||
a_result = a.key_export_secret(pattern=None)
|
||||
b_result = b.key_export_secret(pattern=None)
|
||||
|
||||
if a_result is not None:
|
||||
with open(ascfile, "wb") as f:
|
||||
f.write(a_result)
|
||||
os.chmod(ascfile, 0o600)
|
||||
else:
|
||||
pass
|
||||
|
||||
if b_result is not None:
|
||||
with open(gpgfile, "wb") as f:
|
||||
f.write(b_result)
|
||||
os.chmod(gpgfile, 0o600)
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p/>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
12
lang/python/docs/dita/howto/part03/exporting.dita
Normal file
12
lang/python/docs/dita/howto/part03/exporting.dita
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="exporting-keys">
|
||||
<title>Exporting Keys</title>
|
||||
<body>
|
||||
<p>Exporting keys remains a reasonably simple task, but has been separated into three
|
||||
different functions for the OpenPGP cryptographic engine. Two of those functions are for
|
||||
exporting public keys and the third is for exporting secret keys.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
37
lang/python/docs/dita/howto/part03/get-key.dita
Normal file
37
lang/python/docs/dita/howto/part03/get-key.dita
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_j3h_5my_5db">
|
||||
<title>Get Key</title>
|
||||
<body>
|
||||
<p>An alternative method of getting a single key via its fingerprint is available
|
||||
directly within a Context with Context().get_key. This is the preferred method of selecting
|
||||
a key in order to modify it, sign or certify it and for obtaining relevant data about a
|
||||
single key as a part of other functions; when verifying a signature made by that key, for
|
||||
instance.</p>
|
||||
<p>By default this method will select public keys, but it can select secret keys as well.</p>
|
||||
<p>This first example demonstrates selecting the current key of Werner Koch, which is due to
|
||||
expire at the end of 2018:</p>
|
||||
<p>
|
||||
<codeblock id="getkey-1" outputclass="language-python">import gpg
|
||||
|
||||
fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367"
|
||||
key = gpg.Context().get_key(fingerprint)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>Whereas this example demonstrates selecting the author's current key with the secret key
|
||||
word argument set to True:</p>
|
||||
<p>
|
||||
<codeblock id="getkey-2" outputclass="language-python">import gpg
|
||||
|
||||
fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D"
|
||||
key = gpg.Context().get_key(fingerprint, secret=True)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>It is, of course, quite possible to select expired, disabled and revoked keys with this
|
||||
function, but only to effectively display information about those keys.</p>
|
||||
<p>It is also possible to use both unicode or string literals and byte literals with the
|
||||
fingerprint when getting a key in this way.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
74
lang/python/docs/dita/howto/part03/importing-eff-keys.dita
Normal file
74
lang/python/docs/dita/howto/part03/importing-eff-keys.dita
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="eff-key-import">
|
||||
<title>Importing Keys</title>
|
||||
<shortdesc>DRAFT VERSION</shortdesc>
|
||||
<body>
|
||||
<p>Importing keys is possible with the <codeph>key_import()</codeph> method and takes one
|
||||
argument which is a bytes literal object containing either the binary or ASCII armoured key
|
||||
data for one or more keys.</p>
|
||||
<p>In the following example a key will be retrieved from the SKS keyservers via the web using
|
||||
the requests module. Since requests returns the content as a bytes literal object, we can
|
||||
then use that directly to import the resulting data into our keybox. In order to demonstrate
|
||||
multiple imports this example searches for all the keys of users at a particular domain
|
||||
name. This time we're using the EFF, since they've always been such good supporters of
|
||||
strong encryption and good security practices.</p>
|
||||
<p>If this holds true then I would expect that some keys I already have will be updated and
|
||||
some others will be added. Most of the keys created most recently and belonging to still
|
||||
active people within the EFF should, if they are following their own recent statements, be
|
||||
revoked. If they are not revoked then it would be best left to the reader to determine
|
||||
whether or not the change in leadership at that organisation indicates a change in their
|
||||
policy of supporting good security practices.</p>
|
||||
<p>
|
||||
<codeblock id="import-key-1" outputclass="language-python">import gpg
|
||||
import requests
|
||||
|
||||
c = gpg.Context()
|
||||
url = "https://sks-keyservers.net/pks/lookup"
|
||||
pattern = input("Enter the pattern to search for key or user IDs: ")
|
||||
payload = { "op": "get", "search": pattern }
|
||||
|
||||
r = requests.get(url, verify=True, params=payload)
|
||||
k = c.key_import(r.content)
|
||||
|
||||
summary = """
|
||||
Total number of keys: {0}
|
||||
Total number imported: {1}
|
||||
Number of version 3 keys ignored: {2}
|
||||
|
||||
Number of imported key objects or updates: {3}
|
||||
Number of unchanged keys: {4}
|
||||
Number of new signatures: {5}
|
||||
Number of revoked keys: {6}
|
||||
""".format(k.considered, len(k.imports), k.skipped_v3_keys, k.imported,
|
||||
k.unchanged, k.new_signatures, k.new_revocations)
|
||||
|
||||
print(summary)</codeblock>
|
||||
</p>
|
||||
<p>The resulting output in that case, where the search pattern entered was
|
||||
<codeph>@eff.org</codeph> was:</p>
|
||||
<p>
|
||||
<codeblock id="import-key-2" outputclass="language-bourne">Total number of keys: 272
|
||||
Total number imported: 249
|
||||
Number of version 3 keys ignored: 23
|
||||
|
||||
Number of imported key objects or updates: 180
|
||||
Number of unchanged keys: 66
|
||||
Number of new signatures: 7
|
||||
Number of revoked keys: 0</codeblock>
|
||||
</p>
|
||||
<p>The 23 skipped keys all date back to the 1990s, some of which were made very shortly after
|
||||
PGP 2 was first released.</p>
|
||||
<p>
|
||||
<note>Pretty Good Privacy version 2 and above are the only versions with any widespread use.
|
||||
Pretty Good Privacy version 1 had a number of serious security problems, not least of
|
||||
which being that it relied on an encryption algorithm called Bass-O-Matic which was
|
||||
written by Phil Zimmermann. Following feedback on this algorithm, Zimmermann withdrew
|
||||
version 1 and re-implemented version 2 using RSA and IDEA, even though both were subject
|
||||
to software patents at the time (both of those software patents have long since
|
||||
expired).</note>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
67
lang/python/docs/dita/howto/part03/importing.dita
Normal file
67
lang/python/docs/dita/howto/part03/importing.dita
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="importing-keys">
|
||||
<title>Importing keys</title>
|
||||
<body>
|
||||
<p>Importing keys is possible with the <codeph>key_import()</codeph> method and takes one
|
||||
argument which is a bytes literal object containing either the binary or ASCII armoured key
|
||||
data for one or more keys.</p>
|
||||
<p>The following example retrieves one or more keys from the SKS keyservers via the web using
|
||||
the requests module. Since requests returns the content as a bytes literal object, we can
|
||||
then use that directly to import the resulting data into our keybox.</p>
|
||||
<p>
|
||||
<codeblock id="key-import-01" outputclass="language-python">import gpg
|
||||
import os.path
|
||||
import requests
|
||||
|
||||
c = gpg.Context()
|
||||
url = "https://sks-keyservers.net/pks/lookup"
|
||||
pattern = input("Enter the pattern to search for key or user IDs: ")
|
||||
payload = { "op": "get", "search": pattern }
|
||||
|
||||
r = requests.get(url, verify=True, params=payload)
|
||||
result = c.key_import(r.content)
|
||||
|
||||
if result is not None and hasattr(result, "considered") is False:
|
||||
print(result)
|
||||
elif result is not None and hasattr(result, "considered") is True:
|
||||
num_keys = len(result.imports)
|
||||
new_revs = result.new_revocations
|
||||
new_sigs = result.new_signatures
|
||||
new_subs = result.new_sub_keys
|
||||
new_uids = result.new_user_ids
|
||||
new_scrt = result.secret_imported
|
||||
nochange = result.unchanged
|
||||
print("""
|
||||
The total number of keys considered for import was: {0}
|
||||
|
||||
Number of keys revoked: {1}
|
||||
Number of new signatures: {2}
|
||||
Number of new subkeys: {3}
|
||||
Number of new user IDs: {4}
|
||||
Number of new secret keys: {5}
|
||||
Number of unchanged keys: {6}
|
||||
|
||||
The key IDs for all considered keys were:
|
||||
""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt,
|
||||
nochange))
|
||||
for i in range(num_keys):
|
||||
print(result.imports[i].fpr)
|
||||
print("")
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>
|
||||
<note>When searching for a key ID of any length or a fingerprint (without spaces), the SKS
|
||||
servers require the the leading <codeph>0x</codeph> indicative of hexadecimal be included.
|
||||
Also note that the old short key IDs (e.g. <codeph>0xDEADBEEF</codeph>) should no longer
|
||||
be used due to the relative ease by which such key IDs can be reproduced, as demonstrated
|
||||
by the <xref href="https://evil32.com/" format="html" scope="external">Evil32
|
||||
Project</xref> in 2014 (which was subsequently exploited in 2016).</note>
|
||||
</p>
|
||||
<p/>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
31
lang/python/docs/dita/howto/part03/key-counting.dita
Normal file
31
lang/python/docs/dita/howto/part03/key-counting.dita
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_jgw_wly_5db">
|
||||
<title>Counting Keys</title>
|
||||
<body>
|
||||
<p>Counting the number of keys in your public keybox (<filepath>pubring.kbx</filepath>), the
|
||||
format which has superseded the old keyring format (<filepath>pubring.gpg</filepath> and
|
||||
<filepath>secring.gpg</filepath>), or the number of secret keys is a very simple task.</p>
|
||||
<p>
|
||||
<codeblock id="kc" outputclass="language-python">import gpg
|
||||
|
||||
c = gpg.Context()
|
||||
seckeys = c.keylist(pattern=None, secret=True)
|
||||
pubkeys = c.keylist(pattern=None, secret=False)
|
||||
|
||||
seclist = list(seckeys)
|
||||
secnum = len(seclist)
|
||||
|
||||
publist = list(pubkeys)
|
||||
pubnum = len(publist)
|
||||
|
||||
print("""
|
||||
Number of secret keys: {0}
|
||||
Number of public keys: {1}
|
||||
""".format(secnum, pubnum))
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
53
lang/python/docs/dita/howto/part03/key-selection.dita
Normal file
53
lang/python/docs/dita/howto/part03/key-selection.dita
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_flg_p3y_5db">
|
||||
<title>Key Selection</title>
|
||||
<body>
|
||||
<p>Selecting keys to encrypt to or to sign with will be a common occurrence when working with
|
||||
GPGMe and the means available for doing so are quite simple.</p>
|
||||
<p>They do depend on utilising a Context; however once the data is recorded in another
|
||||
variable, that Context does not need to be the same one which subsequent operations are
|
||||
performed.</p>
|
||||
<p>The easiest way to select a specific key is by searching for that key's key ID or
|
||||
fingerprint, preferably the full fingerprint without any spaces in it. A long key ID will
|
||||
probably be okay, but is not advised and short key IDs are already a problem with some being
|
||||
generated to match specific patterns. It does not matter whether the pattern is upper or
|
||||
lower case.</p>
|
||||
<p>So this is the best method:</p>
|
||||
<p>
|
||||
<codeblock id="keysel-01" outputclass="language-python">import gpg
|
||||
|
||||
k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF")
|
||||
keys = list(k)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>This is passable and very likely to be common:</p>
|
||||
<p>
|
||||
<codeblock id="keysel-02" outputclass="language-python">import gpg
|
||||
|
||||
k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF")
|
||||
keys = list(k)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>And this is a really bad idea:</p>
|
||||
<p>
|
||||
<codeblock id="keysel-03" outputclass="language-python">import gpg
|
||||
|
||||
k = gpg.Context().keylist(pattern="0xDEADBEEF")
|
||||
keys = list(k)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>Alternatively it may be that the intention is to create a list of keys which all match a
|
||||
particular search string. For instance all the addresses at a particular domain, like
|
||||
this:</p>
|
||||
<p>
|
||||
<codeblock id="keysel-04" outputclass="language-python">import gpg
|
||||
|
||||
ncsc = gpg.Context().keylist(pattern="ncsc.mil")
|
||||
nsa = list(ncsc)
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
12
lang/python/docs/dita/howto/part04/basic-functions.dita
Normal file
12
lang/python/docs/dita/howto/part04/basic-functions.dita
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_w5f_zpy_5db">
|
||||
<title>Basic Functions</title>
|
||||
<body>
|
||||
<p>The most frequently called features of any cryptographic library will be the most
|
||||
fundamental tasks for encryption software. In this section we will look at how to
|
||||
programmatically encrypt data, decrypt it, sign it and verify signatures.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
42
lang/python/docs/dita/howto/part04/clear-signing.dita
Normal file
42
lang/python/docs/dita/howto/part04/clear-signing.dita
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_ydy_5qz_5db">
|
||||
<title>Clear Signatures</title>
|
||||
<body>
|
||||
<p>Though PGP/in-line messages are no longer encouraged in favour of PGP/MIME, there is still
|
||||
sometimes value in utilising in-line signatures. This is where clear-signed messages or text
|
||||
is of value.</p>
|
||||
<p>
|
||||
<codeblock id="clrsig-1" outputclass="language-python">import gpg
|
||||
|
||||
text0 = """Declaration of ... something.
|
||||
|
||||
"""
|
||||
text = text0.encode()
|
||||
|
||||
c = gpg.Context()
|
||||
signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR)
|
||||
|
||||
with open("/path/to/statement.txt.asc", "w") as afile:
|
||||
afile.write(signed_data.decode())
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>In spite of the appearance of a clear-signed message, the data handled by GPGME in signing
|
||||
it must still be byte literals.</p>
|
||||
<p>
|
||||
<codeblock id="clrsig-2" outputclass="language-python">import gpg
|
||||
|
||||
with open("/path/to/statement.txt", "rb") as tfile:
|
||||
text = tfile.read()
|
||||
|
||||
c = gpg.Context()
|
||||
signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR)
|
||||
|
||||
with open("/path/to/statement.txt.asc", "wb") as afile:
|
||||
afile.write(signed_data)
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
49
lang/python/docs/dita/howto/part04/decryption.dita
Normal file
49
lang/python/docs/dita/howto/part04/decryption.dita
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_vqx_tqy_5db">
|
||||
<title>Decryption</title>
|
||||
<body>
|
||||
<p>Decrypting something encrypted to a key in one's secret keyring is fairly straight
|
||||
forward.</p>
|
||||
<p>In this example code, however, preconfiguring either <codeph>gpg.Context()</codeph> or
|
||||
<codeph>gpg.core.Context()</codeph> as <codeph>c</codeph> is unnecessary because there is
|
||||
no need to modify the Context prior to conducting the decryption and since the Context is
|
||||
only used once, setting it to c simply adds lines for no gain.</p>
|
||||
<p>
|
||||
<codeblock id="decry-1" outputclass="language-python">import gpg
|
||||
|
||||
ciphertext = input("Enter path and filename of encrypted file: ")
|
||||
newfile = input("Enter path and filename of file to save decrypted data to: ")
|
||||
|
||||
with open(ciphertext, "rb") as cfile:
|
||||
try:
|
||||
plaintext, result, verify_result = gpg.Context().decrypt(cfile)
|
||||
except gpg.errors.GPGMEError as e:
|
||||
plaintext = None
|
||||
print(e)
|
||||
|
||||
if plaintext is not None:
|
||||
with open(newfile, "wb") as nfile:
|
||||
nfile.write(plaintext)
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>The data available in <codeph>plaintext</codeph> following a successful decryption in this
|
||||
example is the decrypted content as a byte object, the recipient key IDs and algorithms in
|
||||
<codeph>result</codeph> and the results of verifying any signatures of the data in
|
||||
<codeph>verify_result</codeph>.</p>
|
||||
<p>
|
||||
<note>The graceful handling of <codeph>GPGMEError</codeph> with the try/except statement is
|
||||
to handle the decryption error message produced if the file <codeph>ciphertext</codeph>,
|
||||
and thus <codeph>cfile</codeph>, are encrypted with deprecated and insecure methods.
|
||||
Particularly without MDC integrity checks or utilising deprecated encryption algorithms.
|
||||
Messages and files encrypted with these are not decrypted with GPGME at all and any user
|
||||
requiring archival access will need to access it manually with pre-GnuPG 2.3 versions of
|
||||
the software which meets the requirements of the specific use case.</note>
|
||||
</p>
|
||||
<p/>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
51
lang/python/docs/dita/howto/part04/default-signing.dita
Normal file
51
lang/python/docs/dita/howto/part04/default-signing.dita
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_ntx_sqz_5db">
|
||||
<title>Default Signatures</title>
|
||||
<body>
|
||||
<p>The normal or default signing process is essentially the same as is most often
|
||||
invoked when also encrypting a message or file. So when the encryption component is not
|
||||
utilised, the result is to produce an encoded and signed output which may or may not be
|
||||
ASCII armoured and which may or may not also be compressed.</p>
|
||||
<p>By default compression will be used unless GnuPG detects that the plaintext is already
|
||||
compressed. ASCII armouring will be determined according to the value of
|
||||
<codeph>gpg.Context().armor</codeph>.</p>
|
||||
<p>The compression algorithm is selected in much the same way as the symmetric encryption
|
||||
algorithm or the hash digest algorithm is when multiple keys are involved; from the
|
||||
preferences saved into the key itself or by comparison with the preferences with all other
|
||||
keys involved.</p>
|
||||
<p>
|
||||
<codeblock id="defsig-1" outputclass="language-python">import gpg
|
||||
|
||||
text0 = """Declaration of ... something.
|
||||
|
||||
"""
|
||||
text = text0.encode()
|
||||
|
||||
c = gpg.Context(armor=True, signers=sig_src)
|
||||
signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL)
|
||||
|
||||
with open("/path/to/statement.txt.asc", "w") as afile:
|
||||
afile.write(signed_data.decode())
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>Though everything in this example is accurate, it is more likely that reading the input
|
||||
data from another file and writing the result to a new file will be performed more like the
|
||||
way it is done in the next example. Even if the output format is ASCII armoured.</p>
|
||||
<p>
|
||||
<codeblock id="defsig-2" outputclass="language-python">import gpg
|
||||
|
||||
with open("/path/to/statement.txt", "rb") as tfile:
|
||||
text = tfile.read()
|
||||
|
||||
c = gpg.Context()
|
||||
signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL)
|
||||
|
||||
with open("/path/to/statement.txt.sig", "wb") as afile:
|
||||
afile.write(signed_data)
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
42
lang/python/docs/dita/howto/part04/detached-signing.dita
Normal file
42
lang/python/docs/dita/howto/part04/detached-signing.dita
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_rfg_5qz_5db">
|
||||
<title>Detached Signatures</title>
|
||||
<body>
|
||||
<p>Detached signatures will often be needed in programmatic uses of GPGME, either for signing
|
||||
files (e.g. tarballs of code releases) or as a component of message signing (e.g. PGP/MIME
|
||||
encoded email).</p>
|
||||
<p>
|
||||
<codeblock id="detsig-1" outputclass="language-python">import gpg
|
||||
|
||||
text0 = """Declaration of ... something.
|
||||
|
||||
"""
|
||||
text = text0.encode()
|
||||
|
||||
c = gpg.Context(armor=True)
|
||||
signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH)
|
||||
|
||||
with open("/path/to/statement.txt.asc", "w") as afile:
|
||||
afile.write(signed_data.decode())
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>As with normal signatures, detached signatures are best handled as byte literals, even when
|
||||
the output is ASCII armoured.</p>
|
||||
<p>
|
||||
<codeblock id="detsig-2" outputclass="language-python">import gpg
|
||||
|
||||
with open("/path/to/statement.txt", "rb") as tfile:
|
||||
text = tfile.read()
|
||||
|
||||
c = gpg.Context(signers=sig_src)
|
||||
signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH)
|
||||
|
||||
with open("/path/to/statement.txt.sig", "wb") as afile:
|
||||
afile.write(signed_data)
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
100
lang/python/docs/dita/howto/part04/encrypt-to-many.dita
Normal file
100
lang/python/docs/dita/howto/part04/encrypt-to-many.dita
Normal file
@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_wmg_tjz_5db">
|
||||
<title>Encrypting to Multiple Keys</title>
|
||||
<body>
|
||||
<p>Encrypting to multiple keys essentially just expands upon the key selection process
|
||||
and the recipients from the previous examples.</p>
|
||||
<p>The following example encrypts a message (<codeph>text</codeph>) to everyone with an email
|
||||
address on the <codeph>gnupg.org</codeph> domain,<fn>You probably don't really want to do
|
||||
this. Searching the keyservers for "gnupg.org" produces over 400 results, the majority of
|
||||
which aren't actually at the gnupg.org domain, but just included a comment regarding the
|
||||
project in their key somewhere.</fn> but does <i>not</i> encrypt to a default key or other
|
||||
key which is configured to normally encrypt to.</p>
|
||||
<p>
|
||||
<codeblock id="enc2-1" outputclass="language-python">import gpg
|
||||
|
||||
text = b"""Oh look, another test message.
|
||||
|
||||
The same rules apply as with the previous example and more likely
|
||||
than not, the message will actually be drawn from reading the
|
||||
contents of a file or, maybe, from entering data at an input()
|
||||
prompt.
|
||||
|
||||
Since the text in this case must be bytes, it is most likely that
|
||||
the input form will be a separate file which is opened with "rb"
|
||||
as this is the simplest method of obtaining the correct data
|
||||
format.
|
||||
"""
|
||||
|
||||
c = gpg.Context(armor=True)
|
||||
rpattern = list(c.keylist(pattern="@gnupg.org", secret=False))
|
||||
logrus = []
|
||||
|
||||
for i in range(len(rpattern)):
|
||||
if rpattern[i].can_encrypt == 1:
|
||||
logrus.append(rpattern[i])
|
||||
|
||||
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, sign=False,
|
||||
always_trust=True)
|
||||
|
||||
with open("secret_plans.txt.asc", "wb") as f:
|
||||
f.write(ciphertext)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>All it would take to change the above example to sign the message and also encrypt the
|
||||
message to any configured default keys would be to change the <codeph>c.encrypt</codeph>
|
||||
line to this:</p>
|
||||
<p>
|
||||
<codeblock id="enc2-2" outputclass="language-python">ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
|
||||
always_trust=True,
|
||||
add_encrypt_to=True)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>The only keyword arguments requiring modification are those for which the default values
|
||||
are changing. The default value of <codeph>sign</codeph> is <codeph>True</codeph>, the
|
||||
default of <codeph>always_trust</codeph> is <codeph>False</codeph>, the default of
|
||||
<codeph>add_encrypt_to</codeph> is <codeph>False</codeph>.</p>
|
||||
<p>If <codeph>always_trust</codeph> is not set to <codeph>True</codeph> and any of the
|
||||
recipient keys are not trusted (e.g. not signed or locally signed) then the encryption will
|
||||
raise an error. It is possible to mitigate this somewhat with something more like this:</p>
|
||||
<p>
|
||||
<codeblock id="enc2-3" outputclass="language-python">import gpg
|
||||
|
||||
with open("secret_plans.txt.asc", "rb") as f:
|
||||
text = f.read()
|
||||
|
||||
c = gpg.Context(armor=True)
|
||||
rpattern = list(c.keylist(pattern="@gnupg.org", secret=False))
|
||||
logrus = []
|
||||
|
||||
for i in range(len(rpattern)):
|
||||
if rpattern[i].can_encrypt == 1:
|
||||
logrus.append(rpattern[i])
|
||||
|
||||
try:
|
||||
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
|
||||
add_encrypt_to=True)
|
||||
except gpg.errors.InvalidRecipients as e:
|
||||
for i in range(len(e.recipients)):
|
||||
for n in range(len(logrus)):
|
||||
if logrus[n].fpr == e.recipients[i].fpr:
|
||||
logrus.remove(logrus[n])
|
||||
else:
|
||||
pass
|
||||
try:
|
||||
ciphertext, result, sign_result = c.encrypt(text, recipients=logrus,
|
||||
add_encrypt_to=True)
|
||||
except:
|
||||
pass
|
||||
|
||||
with open("secret_plans.txt.asc", "wb") as f:
|
||||
f.write(ciphertext)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>This will attempt to encrypt to all the keys searched for, then remove invalid recipients
|
||||
if it fails and try again.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
83
lang/python/docs/dita/howto/part04/encrypt-to-one.dita
Normal file
83
lang/python/docs/dita/howto/part04/encrypt-to-one.dita
Normal file
@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_dkk_sjz_5db">
|
||||
<title>Encrypting to One Key</title>
|
||||
<body>
|
||||
<p>Once the the Context is set the main issues with encrypting data is essentially reduced to
|
||||
key selection and the keyword arguments specified in the
|
||||
<codeph>gpg.Context().encrypt()</codeph> method.</p>
|
||||
<p>Those keyword arguments are:</p>
|
||||
<p>
|
||||
<ul id="ul_cmt_3kz_5db">
|
||||
<li><codeph>recipients</codeph>, a list of keys encrypted to (covered in greater detail in
|
||||
the following section);</li>
|
||||
<li><codeph>sign</codeph>, whether or not to sign the plaintext data, see subsequent
|
||||
sections on signing and verifying signatures below (defaults to
|
||||
<codeph>True</codeph>);</li>
|
||||
<li><codeph>sink</codeph>, to write results or partial results to a secure sink instead of
|
||||
returning it (defaults to <codeph>None</codeph>);</li>
|
||||
<li><codeph>passphrase</codeph>, only used when utilising symmetric encryption (defaults
|
||||
to <codeph>None</codeph>);</li>
|
||||
<li><codeph>always_trust</codeph>, used to override the trust model settings for recipient
|
||||
keys (defaults to <codeph>False</codeph>);</li>
|
||||
<li><codeph>add_encrypt_to</codeph>, utilises any preconfigured encrypt-to or default-key
|
||||
settings in the user's <filepath>gpg.conf</filepath> file (defaults to
|
||||
<codeph>False</codeph>);</li>
|
||||
<li><codeph>prepare</codeph>, prepare for encryption (defaults to
|
||||
<codeph>False</codeph>);</li>
|
||||
<li><codeph>expect_sign</codeph>, prepare for signing (defaults to
|
||||
<codeph>False</codeph>);</li>
|
||||
<li><codeph>compress</codeph>, compresses the plaintext prior to encryption (defaults to
|
||||
<codeph>True</codeph>).</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<codeblock id="enc1-1" outputclass="language-python">import gpg
|
||||
|
||||
a_key = "0x12345678DEADBEEF"
|
||||
text = b"""Some text to test with.
|
||||
|
||||
Since the text in this case must be bytes, it is most likely that
|
||||
the input form will be a separate file which is opened with "rb"
|
||||
as this is the simplest method of obtaining the correct data
|
||||
format.
|
||||
"""
|
||||
|
||||
c = gpg.Context(armor=True)
|
||||
rkey = list(c.keylist(pattern=a_key, secret=False))
|
||||
ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False)
|
||||
|
||||
with open("secret_plans.txt.asc", "wb") as f:
|
||||
f.write(ciphertext)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>Though this is even more likely to be used like this; with the plaintext input read from a
|
||||
file, the recipient keys used for encryption regardless of key trust status and the
|
||||
encrypted output also encrypted to any preconfigured keys set in the
|
||||
<filepath>gpg.conf</filepath> file:</p>
|
||||
<p>
|
||||
<codeblock id="enc1-2" outputclass="language-python">import gpg
|
||||
|
||||
a_key = "0x12345678DEADBEEF"
|
||||
|
||||
with open("secret_plans.txt", "rb") as f:
|
||||
text = f.read()
|
||||
|
||||
c = gpg.Context(armor=True)
|
||||
rkey = list(c.keylist(pattern=a_key, secret=False))
|
||||
ciphertext, result, sign_result = c.encrypt(text, recipients=rkey,
|
||||
sign=True, always_trust=True,
|
||||
add_encrypt_to=True)
|
||||
|
||||
with open("secret_plans.txt.asc", "wb") as f:
|
||||
f.write(ciphertext)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>If the <codeph>recipients</codeph> paramater is empty then the plaintext is encrypted
|
||||
symmetrically. If no <codeph>passphrase</codeph> is supplied as a parameter or via a
|
||||
callback registered with the <codeph>Context()</codeph> then an out-of-band prompt for the
|
||||
passphrase via pinentry will be invoked.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
12
lang/python/docs/dita/howto/part04/encryption.dita
Normal file
12
lang/python/docs/dita/howto/part04/encryption.dita
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_on2_nqy_5db">
|
||||
<title>Encryption</title>
|
||||
<body>
|
||||
<p>Encrypting is very straight forward. In the first example below the message,
|
||||
<codeph>text</codeph>, is encrypted to a single recipient's key. In the second example the
|
||||
message will be encrypted to multiple recipients.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_dpb_fqz_5db">
|
||||
<title>Signing Key Selection</title>
|
||||
<body>
|
||||
<p>By default GPGME and the Python bindings will use the default key configured for the user
|
||||
invoking the GPGME API. If there is no default key specified and there is more than one
|
||||
secret key available it may be necessary to specify the key or keys with which to sign
|
||||
messages and files.</p>
|
||||
<p>
|
||||
<codeblock id="sigkey-1" outputclass="language-python">import gpg
|
||||
|
||||
logrus = input("Enter the email address or string to match signing keys to: ")
|
||||
hancock = gpg.Context().keylist(pattern=logrus, secret=True)
|
||||
sig_src = list(hancock)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>The signing examples in the following sections include the explicitly designated
|
||||
<codeph>signers</codeph> parameter in two of the five examples; once where the resulting
|
||||
signature would be ASCII armoured and once where it would not be armoured.</p>
|
||||
<p>While it would be possible to enter a key ID or fingerprint here to match a specific key,
|
||||
it is not possible to enter two fingerprints and match two keys since the patten expects a
|
||||
string, bytes or None and not a list. A string with two fingerprints won't match any single
|
||||
key.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
11
lang/python/docs/dita/howto/part04/signing.dita
Normal file
11
lang/python/docs/dita/howto/part04/signing.dita
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_nqk_vqy_5db">
|
||||
<title>Signing Text and Files</title>
|
||||
<body>
|
||||
<p>The following sections demonstrate how to specify keys to sign with and the types of
|
||||
signatures which can be made.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
150
lang/python/docs/dita/howto/part04/verification.dita
Normal file
150
lang/python/docs/dita/howto/part04/verification.dita
Normal file
@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_p3g_yqy_5db">
|
||||
<title>Signature Verification</title>
|
||||
<body>
|
||||
<p>Essentially there are two principal methods of verification of a signature. The first
|
||||
of these is for use with the normal or default signing method and for clear-signed messages.
|
||||
The second is for use with files and data with detached signatures.</p>
|
||||
<p>The following example is intended for use with the default signing method where the file
|
||||
was not ASCII armoured:</p>
|
||||
<p>
|
||||
<codeblock id="verify-1" outputclass="language-python">import gpg
|
||||
import time
|
||||
|
||||
filename = "statement.txt"
|
||||
gpg_file = "statement.txt.gpg"
|
||||
|
||||
c = gpg.Context()
|
||||
|
||||
try:
|
||||
data, result = c.verify(open(gpg_file))
|
||||
verified = True
|
||||
except gpg.errors.BadSignatures as e:
|
||||
verified = False
|
||||
print(e)
|
||||
|
||||
if verified is True:
|
||||
for i in range(len(result.signatures)):
|
||||
sign = result.signatures[i]
|
||||
print("""Good signature from:
|
||||
{0}
|
||||
with key {1}
|
||||
made at {2}
|
||||
""".format(c.get_key(sign.fpr).uids[0].uid,
|
||||
sign.fpr, time.ctime(sign.timestamp)))
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>Whereas this next example, which is almost identical would work with normal ASCII armoured
|
||||
files and with clear-signed files:</p>
|
||||
<p>
|
||||
<codeblock id="verify-2" outputclass="language-python">import gpg
|
||||
import time
|
||||
|
||||
filename = "statement.txt"
|
||||
asc_file = "statement.txt.asc"
|
||||
|
||||
c = gpg.Context()
|
||||
|
||||
try:
|
||||
data, result = c.verify(open(asc_file))
|
||||
verified = True
|
||||
except gpg.errors.BadSignatures as e:
|
||||
verified = False
|
||||
print(e)
|
||||
|
||||
if verified is True:
|
||||
for i in range(len(result.signatures)):
|
||||
sign = result.signatures[i]
|
||||
print("""Good signature from:
|
||||
{0}
|
||||
with key {1}
|
||||
made at {2}
|
||||
""".format(c.get_key(sign.fpr).uids[0].uid,
|
||||
sign.fpr, time.ctime(sign.timestamp)))
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>In both of the previous examples it is also possible to compare the original data that was
|
||||
signed against the signed data in <codeph>data</codeph> to see if it matches with something
|
||||
like this:</p>
|
||||
<p>
|
||||
<codeblock id="verify-3" outputclass="language-python">with open(filename, "rb") as afile:
|
||||
text = afile.read()
|
||||
|
||||
if text == data:
|
||||
print("Good signature.")
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>The following two examples, however, deal with detached signatures. With his method of
|
||||
verification the data that was signed does not get returned since it is already being
|
||||
explicitly referenced in the first argument of <codeph>c.verify</codeph>. So
|
||||
<codeph>data</codeph> is <codeph>None</codeph> and only the information in
|
||||
<codeph>result</codeph> is available.</p>
|
||||
<p>
|
||||
<codeblock id="verify-4" outputclass="language-python">import gpg
|
||||
import time
|
||||
|
||||
filename = "statement.txt"
|
||||
sig_file = "statement.txt.sig"
|
||||
|
||||
c = gpg.Context()
|
||||
|
||||
try:
|
||||
data, result = c.verify(open(filename), open(sig_file))
|
||||
verified = True
|
||||
except gpg.errors.BadSignatures as e:
|
||||
verified = False
|
||||
print(e)
|
||||
|
||||
if verified is True:
|
||||
for i in range(len(result.signatures)):
|
||||
sign = result.signatures[i]
|
||||
print("""Good signature from:
|
||||
{0}
|
||||
with key {1}
|
||||
made at {2}
|
||||
""".format(c.get_key(sign.fpr).uids[0].uid,
|
||||
sign.fpr, time.ctime(sign.timestamp)))
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>
|
||||
<codeblock id="verify-5" outputclass="language-python">import gpg
|
||||
import time
|
||||
|
||||
filename = "statement.txt"
|
||||
asc_file = "statement.txt.asc"
|
||||
|
||||
c = gpg.Context()
|
||||
|
||||
try:
|
||||
data, result = c.verify(open(filename), open(asc_file))
|
||||
verified = True
|
||||
except gpg.errors.BadSignatures as e:
|
||||
verified = False
|
||||
print(e)
|
||||
|
||||
if verified is not None:
|
||||
for i in range(len(result.signatures)):
|
||||
sign = result.signatures[i]
|
||||
print("""Good signature from:
|
||||
{0}
|
||||
with key {1}
|
||||
made at {2}
|
||||
""".format(c.get_key(sign.fpr).uids[0].uid,
|
||||
sign.fpr, time.ctime(sign.timestamp)))
|
||||
else:
|
||||
pass
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
39
lang/python/docs/dita/howto/part05/add-uid.dita
Normal file
39
lang/python/docs/dita/howto/part05/add-uid.dita
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_e4q_jyz_5db">
|
||||
<title>Adding a User ID</title>
|
||||
<body>
|
||||
<p>By comparison to creating primary keys and subkeys, adding a new user ID to an existing key
|
||||
is much simpler. The method used to do this is <codeph>key_add_uid</codeph> and the only
|
||||
arguments it takes are for the <codeph>key</codeph> and the new <codeph>uid</codeph>.</p>
|
||||
<p>
|
||||
<codeblock id="adduid-1" outputclass="language-python">import gpg
|
||||
|
||||
c = gpg.Context()
|
||||
c.home_dir = "~/.gnupg-dm"
|
||||
|
||||
dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
|
||||
key = c.get_key(dmfpr, secret=True)
|
||||
uid = "Danger Mouse <danger.mouse@secret.example.net>"
|
||||
|
||||
c.key_add_uid(key, uid)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>Unsurprisingly the result of this is:</p>
|
||||
<p>
|
||||
<codeblock id="adduid-2" outputclass="language-bourne">bash-4.4$ gpg --homedir ~/.gnupg-dm -K
|
||||
~/.gnupg-dm/pubring.kbx
|
||||
----------------------
|
||||
sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15]
|
||||
177B7C25DB99745EE2EE13ED026D2F19E99E63AA
|
||||
uid [ultimate] Danger Mouse <danger.mouse@secret.example.net>
|
||||
uid [ultimate] Danger Mouse <dm@secret.example.net>
|
||||
ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13]
|
||||
|
||||
bash-4.4$
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
36
lang/python/docs/dita/howto/part05/certification.dita
Normal file
36
lang/python/docs/dita/howto/part05/certification.dita
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_p15_1yz_5db">
|
||||
<title>Key Certification</title>
|
||||
<body>
|
||||
<p>Since key certification is more frequently referred to as key signing, the method used to
|
||||
perform this function is <codeph>key_sign</codeph>.</p>
|
||||
<p>The <codeph>key_sign</codeph> method takes four arguments: <codeph>key</codeph>,
|
||||
<codeph>uids</codeph>, <codeph>expires_in</codeph> and <codeph>local</codeph>. The default
|
||||
value of <codeph>uids</codeph> is <codeph>None</codeph> and which results in all user IDs
|
||||
being selected. The default value of both <codeph>expires_in</codeph> and
|
||||
<codeph>local</codeph> is <codeph>False</codeph>; which results in the signature never
|
||||
expiring and being able to be exported.</p>
|
||||
<p>The <codeph>key</codeph> is the key being signed rather than the key doing the signing. To
|
||||
change the key doing the signing refer to the signing key selection above for signing
|
||||
messages and files.</p>
|
||||
<p>If the <codeph>uids</codeph> value is not <codeph>None</codeph> then it must either be a
|
||||
string to match a single user ID or a list of strings to match multiple user IDs. In this
|
||||
case the matching of those strings must be precise and it is case sensitive.</p>
|
||||
<p>To sign Danger Mouse's key for just the initial user ID with a signature which will last a
|
||||
little over a month, do this:</p>
|
||||
<p>
|
||||
<codeblock id="cert-1" outputclass="language-python">import gpg
|
||||
|
||||
c = gpg.Context()
|
||||
uid = "Danger Mouse <dm@secret.example.net>"
|
||||
|
||||
dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
|
||||
key = c.get_key(dmfpr, secret=True)
|
||||
c.key_sign(key, uids=uid, expires_in=2764800)
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
34
lang/python/docs/dita/howto/part05/key-creation.dita
Normal file
34
lang/python/docs/dita/howto/part05/key-creation.dita
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_c4z_syd_vdb">
|
||||
<title>Creating Keys and Subkeys</title>
|
||||
<body>
|
||||
<p>The one thing, aside from GnuPG itself, that GPGME depends on, of course, is the keys
|
||||
themselves. So it is necessary to be able to generate them and modify them by adding
|
||||
subkeys, revoking or disabling them, sometimes deleting them and doing the same for user
|
||||
IDs.</p>
|
||||
<p>In the following examples a key will be created for the world's greatest secret agent,
|
||||
Danger Mouse. Since Danger Mouse is a secret agent he needs to be able to protect
|
||||
information to <tt>SECRET</tt> level clearance, so his keys will be 3072-bit keys.</p>
|
||||
<p>The pre-configured <filepath>gpg.conf</filepath> file which sets cipher, digest and other
|
||||
preferences contains the following configuration parameters:</p>
|
||||
<p>
|
||||
<codeblock id="gpg-config">expert
|
||||
allow-freeform-uid
|
||||
allow-secret-key-import
|
||||
trust-model tofu+pgp
|
||||
tofu-default-policy unknown
|
||||
enable-large-rsa
|
||||
enable-dsa2
|
||||
cert-digest-algo SHA512
|
||||
default-preference-list TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 ZLIB BZIP2 ZIP Uncompressed
|
||||
personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES
|
||||
personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1
|
||||
personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
|
||||
</codeblock>
|
||||
</p>
|
||||
<p/>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
97
lang/python/docs/dita/howto/part05/primary-key.dita
Normal file
97
lang/python/docs/dita/howto/part05/primary-key.dita
Normal file
@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_nfy_byz_5db">
|
||||
<title>Primary Key Creation</title>
|
||||
<body>
|
||||
<p>Generating a primary key uses the <codeph>create_key</codeph> method in a Context. It
|
||||
contains multiple arguments and keyword arguments, including: <codeph>userid</codeph>,
|
||||
<codeph>algorithm</codeph>, <codeph>expires_in</codeph>, <codeph>expires</codeph>,
|
||||
<codeph>sign</codeph>, <codeph>encrypt</codeph>, <codeph>certify</codeph>,
|
||||
<codeph>authenticate</codeph>, <codeph>passphrase</codeph> and <codeph>force</codeph>. The
|
||||
defaults for all of those except <codeph>userid</codeph>, <codeph>algorithm</codeph>,
|
||||
<codeph>expires_in</codeph>, <codeph>expires</codeph> and <codeph>passphrase</codeph> is
|
||||
<codeph>False</codeph>. The defaults for <codeph>algorithm</codeph> and
|
||||
<codeph>passphrase</codeph> is <codeph>None</codeph>. The default for
|
||||
<codeph>expires_in</codeph> is <codeph>0</codeph>. The default for
|
||||
<codeph>expires</codeph> is <codeph>True</codeph>. There is no default for
|
||||
<codeph>userid</codeph>.</p>
|
||||
<p>If <codeph>passphrase</codeph> is left as <codeph>None</codeph> then the key will not be
|
||||
generated with a passphrase, if <codeph>passphrase</codeph> is set to a string then that
|
||||
will be the passphrase and if <codeph>passphrase</codeph> is set to <codeph>True</codeph>
|
||||
then gpg-agent will launch pinentry to prompt for a passphrase. For the sake of convenience,
|
||||
these examples will keep passphrase set to <codeph>None</codeph>.</p>
|
||||
<p>
|
||||
<codeblock id="keygen-1" outputclass="language-python">import gpg
|
||||
|
||||
c = gpg.Context()
|
||||
|
||||
c.home_dir = "~/.gnupg-dm"
|
||||
userid = "Danger Mouse <dm@secret.example.net>"
|
||||
|
||||
dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000,
|
||||
sign=True, certify=True)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>One thing to note here is the use of setting the <codeph>c.home_dir</codeph> parameter.
|
||||
This enables generating the key or keys in a different location. In this case to keep the
|
||||
new key data created for this example in a separate location rather than adding it to
|
||||
existing and active key store data. As with the default directory,
|
||||
<filepath>~/.gnupg</filepath>, any temporary or separate directory needs the permissions
|
||||
set to only permit access by the directory owner. On posix systems this means setting the
|
||||
directory permissions to <codeph>700</codeph>.</p>
|
||||
<p>The <cmdname>temp-homedir-config.py</cmdname> script in the HOWTO examples directory will
|
||||
create an alternative homedir with these configuration options already set and the correct
|
||||
directory and file permissions.</p>
|
||||
<p>The successful generation of the key can be confirmed via the returned
|
||||
<codeph>GenkeyResult</codeph> object, which includes the following data:</p>
|
||||
<p>
|
||||
<codeblock id="keygen-2" outputclass="language-python">print("""
|
||||
Fingerprint: {0}
|
||||
Primary Key: {1}
|
||||
Public Key: {2}
|
||||
Secret Key: {3}
|
||||
Sub Key: {4}
|
||||
User IDs: {5}
|
||||
""".format(dmkey.fpr, dmkey.primary, dmkey.pubkey, dmkey.seckey, dmkey.sub,
|
||||
dmkey.uid))
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>Alternatively the information can be confirmed using the command line program:</p>
|
||||
<p>
|
||||
<codeblock id="keygen-3" outputclass="language-bourne">bash-4.4$ gpg --homedir ~/.gnupg-dm -K
|
||||
~/.gnupg-dm/pubring.kbx
|
||||
----------------------
|
||||
sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15]
|
||||
177B7C25DB99745EE2EE13ED026D2F19E99E63AA
|
||||
uid [ultimate] Danger Mouse <dm@secret.example.net>
|
||||
|
||||
bash-4.4$
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>As with generating keys manually, to preconfigure expanded preferences for the cipher,
|
||||
digest and compression algorithms, the <filepath>gpg.conf</filepath> file must contain those
|
||||
details in the home directory in which the new key is being generated. I used a cut down
|
||||
version of my own <filepath>gpg.conf</filepath> file in order to be able to generate
|
||||
this:</p>
|
||||
<p>
|
||||
<codeblock id="keygen-4" outputclass="language-bourne">bash-4.4$ gpg --homedir ~/.gnupg-dm --edit-key 177B7C25DB99745EE2EE13ED026D2F19E99E63AA showpref quit
|
||||
Secret key is available.
|
||||
|
||||
sec rsa3072/026D2F19E99E63AA
|
||||
created: 2018-03-15 expires: 2019-03-15 usage: SC
|
||||
trust: ultimate validity: ultimate
|
||||
[ultimate] (1). Danger Mouse <dm@secret.example.net>
|
||||
|
||||
[ultimate] (1). Danger Mouse <dm@secret.example.net>
|
||||
Cipher: TWOFISH, CAMELLIA256, AES256, CAMELLIA192, AES192, CAMELLIA128, AES, BLOWFISH, IDEA, CAST5, 3DES
|
||||
Digest: SHA512, SHA384, SHA256, SHA224, RIPEMD160, SHA1
|
||||
Compression: ZLIB, BZIP2, ZIP, Uncompressed
|
||||
Features: MDC, Keyserver no-modify
|
||||
|
||||
bash-4.4$
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
24
lang/python/docs/dita/howto/part05/rev-uid.dita
Normal file
24
lang/python/docs/dita/howto/part05/rev-uid.dita
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_fbb_lyz_5db">
|
||||
<title>Revoking a User ID</title>
|
||||
<body>
|
||||
<p>Revoking a user ID is a fairly similar process, except that it uses the
|
||||
<codeph>key_revoke_uid</codeph> method.</p>
|
||||
<p>
|
||||
<codeblock id="revuid" outputclass="language-python">import gpg
|
||||
|
||||
c = gpg.Context()
|
||||
c.home_dir = "~/.gnupg-dm"
|
||||
|
||||
dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA"
|
||||
key = c.get_key(dmfpr, secret=True)
|
||||
uid = "Danger Mouse <danger.mouse@secret.example.net>"
|
||||
|
||||
c.key_revoke_uid(key, uid)
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
53
lang/python/docs/dita/howto/part05/subkeys.dita
Normal file
53
lang/python/docs/dita/howto/part05/subkeys.dita
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_cb4_fyz_5db">
|
||||
<title>Subkey Creation</title>
|
||||
<body>
|
||||
<p>Adding subkeys to a primary key is fairly similar to creating the primary key with
|
||||
the <codeph>create_subkey</codeph> method. Most of the arguments are the same, but not quite
|
||||
all. Instead of the <codeph>userid</codeph> argument there is now a <codeph>key</codeph>
|
||||
argument for selecting which primary key to add the subkey to.</p>
|
||||
<p>In the following example an encryption subkey will be added to the primary key. Since
|
||||
Danger Mouse is a security conscious secret agent, this subkey will only be valid for about
|
||||
six months, half the length of the primary key.</p>
|
||||
<p>
|
||||
<codeblock id="subkey-1" outputclass="language-python">import gpg
|
||||
|
||||
c = gpg.Context()
|
||||
c.home_dir = "~/.gnupg-dm"
|
||||
|
||||
key = c.get_key(dmkey.fpr, secret=True)
|
||||
dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000,
|
||||
encrypt=True)
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>As with the primary key, the results here can be checked with:</p>
|
||||
<p>
|
||||
<codeblock id="subkey-2" outputclass="language-python">print("""
|
||||
Fingerprint: {0}
|
||||
Primary Key: {1}
|
||||
Public Key: {2}
|
||||
Secret Key: {3}
|
||||
Sub Key: {4}
|
||||
User IDs: {5}
|
||||
""".format(dmsub.fpr, dmsub.primary, dmsub.pubkey, dmsub.seckey, dmsub.sub,
|
||||
dmsub.uid))
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>As well as on the command line with:</p>
|
||||
<p>
|
||||
<codeblock id="subkey-3" outputclass="language-bourne">bash-4.4$ gpg --homedir ~/.gnupg-dm -K
|
||||
~/.gnupg-dm/pubring.kbx
|
||||
----------------------
|
||||
sec rsa3072 2018-03-15 [SC] [expires: 2019-03-15]
|
||||
177B7C25DB99745EE2EE13ED026D2F19E99E63AA
|
||||
uid [ultimate] Danger Mouse <dm@secret.example.net>
|
||||
ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13]
|
||||
|
||||
bash-4.4$
|
||||
</codeblock>
|
||||
</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
10
lang/python/docs/dita/howto/part05/user-ids.dita
Normal file
10
lang/python/docs/dita/howto/part05/user-ids.dita
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_d1j_hyz_5db">
|
||||
<title>User IDs</title>
|
||||
<body>
|
||||
<p></p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
53
lang/python/docs/dita/howto/part06/group-lines.dita
Normal file
53
lang/python/docs/dita/howto/part06/group-lines.dita
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_gbm_bxz_5db">
|
||||
<title>Group Lines</title>
|
||||
<body>
|
||||
<p>There is not yet an easy way to access groups configured in the
|
||||
<filepath>gpg.conf</filepath> file from within GPGME. As a consequence these central
|
||||
groupings of keys cannot be shared amongst multiple programs, such as MUAs readily.</p>
|
||||
<p>The following code, however, provides a work-around for obtaining this information in
|
||||
Python.</p>
|
||||
<p>
|
||||
<codeblock id="groups-1" outputclass="language-python">import subprocess
|
||||
|
||||
lines = subprocess.getoutput("gpgconf --list-options gpg").splitlines()
|
||||
|
||||
for i in range(len(lines)):
|
||||
if lines[i].startswith("group") is True:
|
||||
line = lines[i]
|
||||
else:
|
||||
pass
|
||||
|
||||
groups = line.split(":")[-1].replace('"', '').split(',')
|
||||
|
||||
group_lines = []
|
||||
group_lists = []
|
||||
|
||||
for i in range(len(groups)):
|
||||
group_lines.append(groups[i].split("="))
|
||||
group_lists.append(groups[i].split("="))
|
||||
|
||||
for i in range(len(group_lists)):
|
||||
group_lists[i][1] = group_lists[i][1].split()
|
||||
</codeblock>
|
||||
</p>
|
||||
<p>The result of that code is that <codeph>group_lines</codeph> is a list of lists where
|
||||
<codeph>group_lines[i][0]</codeph> is the name of the group and
|
||||
<codeph>group_lines[i][1]</codeph> is the key IDs of the group as a string.</p>
|
||||
<p>The <codeph>group_lists</codeph> result is very similar in that it is a list of lists. The
|
||||
first part, <codeph>group_lists[i][0]</codeph> matches <codeph>group_lines[i][0]</codeph> as
|
||||
the name of the group, but <codeph>group_lists[i][1]</codeph> is the key IDs of the group as
|
||||
a string.</p>
|
||||
<p>To use this code as a module use:</p>
|
||||
<p>
|
||||
<codeblock id="groups-2" outputclass="language-python">from groups import group_lists</codeblock>
|
||||
</p>
|
||||
<p>A demonstration of using the <filepath>groups.py</filepath> module is also available in
|
||||
the form of the executable <cmdname>mutt-groups.py</cmdname> script. This second script
|
||||
reads all the group entries in a user's <filepath>gpg.conf</filepath> file and converts them
|
||||
into crypt-hooks suitable for use with the Mutt and Neomutt mail clients.</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
16
lang/python/docs/dita/howto/version-info.dita
Normal file
16
lang/python/docs/dita/howto/version-info.dita
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE dita PUBLIC "-//OASIS//DTD DITA Composite//EN" "ditabase.dtd">
|
||||
<dita xml:lang="en-GB">
|
||||
<topic id="topic_vnz_nn2_vdb">
|
||||
<title>Documentation Version</title>
|
||||
<body>
|
||||
<p><b>Version:</b> 0.1.3-DRAFT</p>
|
||||
<p><b>Author:</b> Ben McGinnes <<xref href="mailto:ben@gnupg.org" format="html"
|
||||
scope="external">ben@gnupg.org</xref>></p>
|
||||
<p><b>Author GPG Key ID:</b>
|
||||
<xref href="http://files.au.adversary.org/crypto/ben-key.asc" format="text" scope="external"
|
||||
>DB4724E6FA4286C92B4E55C4321E4E2373590E5D</xref></p>
|
||||
<p><b>Language:</b> Australian English, British English</p>
|
||||
</body>
|
||||
</topic>
|
||||
</dita>
|
Loading…
Reference in New Issue
Block a user