Idea: EncryptPlugin
I have a need to store passwords securely in TWiki pages, accessible only by a selected group. Passwords need to be strongly encrypted.
There are already two plugins for content encryption:
- TopicCryptPlugin: Encrypt parts of a topic for privacy and add digital signatures to topics -- seems like a comprehensive and secure solution
- HidePasswordPlugin: Designed to hide password embedded in TWiki pages -- totally insecure, passwords are stored in plain text and can be viewed with
raw=on
- HideInEditModePlugin: Hide one or two blocks of text in the edit page -- unclear if secure, obsolete
- EncryptedPagesPlugin: Java applet that provides the ability to store data on a page in an encrypted form -- never finished, obsolete
Of those plugins, only the
TopicCryptPlugin seems to fit the bill, but the syntax is rather complicated for my needs.
Here is the proposed spec of a new
EncryptPlugin:
- User adds
%ENCRYPT{"my secret text"}%.
- On save, it gets converted to:
%ENCRYPT{_dont_change="8ohLxtZj"}%, e.g. a variable containing a hash value.
- Text is stored in encrypted form as custom meta data in the topic, such as
%META:ENCRYPTPLUGIN{name="8ohLxtZj" value="a4sf,4lxot-w#ger^bwe+lk,wvbf:ad"}%
- In view mode,
%ENCRYPT{_dont_change="8ohLxtZj"}% is rendered as follows:
-
my secret text if viewed by author.
-
***** if viewed by non-authorized user.
- In edit mode,
%ENCRYPT{_dont_change="8ohLxtZj"}% is rendered as follows:
-
%ENCRYPT{"my secret text" _dont_change="8ohLxtZj"}% if viewed by author, e.g. author can change the text.
-
%ENCRYPT{_dont_change="8ohLxtZj"}% if viewed by non-authorized user, e.g. they just see the hash value.
- By default, only the author can see and edit encrypted text. It is possible to add an
allow parameter, such as allow="SupportGroup", to restrict access to a group. The _dont_change="8ohLxtZj" hash contains the allow parameter, e.g. gets invalidated if a non-member changes the allow parameter.
Feedback?
--
PeterThoeny - 2010-02-01
I refined above spec a bit.
--
PeterThoeny - 2010-09-01
I created
EncryptPlugin with preliminary spec/doc. Anyone interested in implementing this? I have the code skeleton done sans core functionality (not yet posted).
--
PeterThoeny - 2010-11-15
Looking at
TopicCryptPlugin, there is certainly a lot there which could be reused. We might want to add Blowfish for speed?
I suggest we provide for both
allow and
deny with those values being either Users or Groups, and possibly an optional
display parameter to control what (if anything) is displayed for non-authorized users.
So the Usage would be:
%<nop>ENCRYPT{"text to be encrypted" allow="List of Users, Groups" deny="list of users, groups" display="TWiki text to display to non-authorized users" }%
The
%<nop>META:ENCRYPTPLUGIN{name="..." value="..."}% would be visible in
raw=debug mode. I am not sure this matters? Though it does allow access to the raw encrypted data for someone who is motivated.
For more security, the
allow and
deny parameters could also be encrypted when the topic is viewed in raw mode, or edited by users not authorized.
--
CraigMeyer - 2010-11-29
I thought of just using
allow for simplicity. For security defining an exclusive group for access is more secure. Defining a group that is excluded is more error-prone in daily use.
The META:ENCRYPTPLUGIN meta data is not visible in a raw=on view, but is in a raw=debug view. It does not matter as long as the encryption is secure, such as with an RSA key with enough bits.
The
allow does not need to be encrypted as long as the allow and raw text is encrypted in the meta data. That is, when decrypting based on membership you can check if the decrypted group matches the one in
allow.
--
PeterThoeny - 2010-11-29
I agree with keeping it simple, just use allow.
By the way? Is there a standard function which does the
inList(user, list_string) checking. Meaning, given the User and a comma delimited string of mixed WikiNames and GroupNames... determine if that User is in the list. This something which is probably used all over the code. I found a version in
TagMePlugin
I have started implementation of
EncryptPlugin. I am using
TDD (Test Driven Development), so I have unit tests to check each sub-function. Is there a Unit Test environment for TWiki when just running from the command line?
--
CraigMeyer - 2010-12-02
On group membership test, are you looking for
TWiki::Func::isGroupMember() in
TWikiFuncDotPm?
Great that you are committed to unit testing! See
TestCasesTutorial.
--
PeterThoeny - 2010-12-03
Peter,
Trying to learn the proper process for check-in of a new Plugin?
1) Do I first go to
Develop Bugs WebChanges
and create a new Entry?
creating an Enhancement, State: Being worked on,
EncryptPlugin, waiting for: Me
2) I have checked out the svn trunk (and
TWikiRelease0.5x00)
3) create a new directory in twikiplugins for
EncryptPlugin
4) put the required code, topics in directory
5) Then check everything in?
Thank you,
Craig
--
CraigMeyer - 2010-12-04
As for the support function
TWiki::Func::isGroupMember(). I was looking for something one level up. Here is the code I used, with slight modification from
TagMePlugin
Note: I changed the split to allow for spaces around the comma's in the comma delimited list.
_inList() looks for the given User in the comma-delimited list of Users and Groups.
sub _inList ($$) {
my($user, $comma_str) = @_;
my($name);
foreach $name (split(/\s*,\s*/, $comma_str) ){
$name =~ s/(Main\.|\%MAINWEB\%\.)//go; # strip leading web.
if( $name eq $user ||
(TWiki::Func::isGroup($name) && TWiki::Func::isGroupMember($name, $user)) ){
return( 1 );
}
}
return(0);
} #_inList
--
CraigMeyer - 2010-12-04
Do all plugin work that is not part of the core distribution in the SVN trunk (don't use branches). My preliminary version is already at
SVN:EncryptPlugin
(it already includes all build stuff). Do a checkout of the whole trunk, see
SubversionReadme and base your dev TWiki on this checkout.
Do a symbolic link "install" of all plugins you need using
pseudo-install. Before you do that for EncryptPlugin, temporarily move away your code and topics. After pseudo-install, copy your code and topic back. When ready, build and upload the plugin. See details at
BuildContribCookbook and
PluginsInSubversion.
--
PeterThoeny - 2010-12-04
Oh, I just realized that I never checked in the skeleton code and doc I did in September. I just did. You can to an
svn up on your twiki/trunk checkout, then copy your own code over it.
--
PeterThoeny - 2010-12-05
Ok, I did not find your code, and so started without it. I will do the update first, thanks for warning me
Good News, it is working.
It was written to handle multiple %<nop>ENCRYPT{}% calls per topic
I need to convert my Test::More unit tests into the TWiki unit tests.
I also need to add a few more tests for complete coverage.
It is currently using Blowfish, though it could use RC4.
I need to improve the key generation, handling. It can read/create real RSA keys (public and private), though they aren't being used right now.
I don't usually like to check stuff in, that I am satisfied with, but if you want to see it, I will check it in.
--
CraigMeyer - 2010-12-05
In order to handle multiple encrypts, I need to add an index argument to the META data.
When it signs (not really required) and then MD6 hashes the concatenation of
allow_list +
clear_text +
index, the hash will be unique, even if one just copies the code several times.
Example:
- %ENCRYPT{"%GREEN> Jimmy Neutron %END_COLOR%>" allow="SmallGroup" display="%RED%You won't see this unless you are me %ENDCOLOR%" }%
- %ENCRYPT{"%GREEN> Jimmy Neutron %END_COLOR%>" allow="SmallGroup" display="%RED%You won't see this unless you are me %ENDCOLOR%" }%
- %ENCRYPT{"%GREEN> Jimmy Neutron %END_COLOR%>" allow="SmallGroup" display="%RED%You won't see this unless you are me %ENDCOLOR%" }%
Produces the following Meta:
%<nop>META:ENCRYPTPLUGIN{name="DcoCU7Q8mB+M0P9LHCfULwxUTlMK7zwRcFQ3URdWg/w" allow="SmallGroup" display="%25RED%25 You won't see this unless you are me %25ENDCOLOR%25" index="0" value="U2FsdGVkX1+04smdGiB+FpHmgHobmC7StSzjXmzHIB6fSX93+b6sMzXCY3/TUHhgVqHEt1uXG6w=%0a"}%
%<nop>META:ENCRYPTPLUGIN{name="dBEVUsm8SVElzzXZzBkvuCTWuTk5opcVlKH/+IVu2Mc" allow="SmallGroup" display="%25RED%25 You won't see this unless you are me %25ENDCOLOR%25" index="1" value="U2FsdGVkX1+0j/37uDuzVlpOVduYccmqYsZEEfooFW8ciKvKwTu+X1g04/eIewNaGa1UxItvxlY=%0a"}%
%<nop>META:ENCRYPTPLUGIN{name="cJGOYU+3cUm4VDwL9tvtLTthJ1V+GQGlkrOyFNkqGbE" allow="SmallGroup" display="%25RED%25 You won't see this unless you are me %25ENDCOLOR%25" index="2" value="U2FsdGVkX19i63Pe+OeRvlyCmBhLnVONsBuOpUdAs5kGHE6xebgMfO2Qlm73Q14i6MvkG6qhphY=%0a"}%
--
CraigMeyer - 2010-12-05
Good progress! You do not need an index for the meta data, the
name="..." is the hash key. See docs at
TWikiMetaDotPm, and study how META:FIELD and META:FILEATTACHMENT are implemented. Also look at my skeleton code. For example,
my $value = $meta->get( 'ENCRYPTPLUGIN', $attrs->{_dont_change} ) will return the value for the key stored in the
_dont_change parameter of the ENCRYPT variable.
--
PeterThoeny - 2010-12-05
The index is not for access. It is used to disambiguate repeated instances of the exact same %<nop>ENCRYPT{...}% statements. So that each usage has a corresponding META element.
By the way I checked it in late last night. I still need to fix the RC4 code, and setup the proper config handling for the password itself.
--
CraigMeyer - 2010-12-05
This plugin brings up an interesting question. Let's say this plugin is in use, in several topics. How do we handle an Admin changing the password? This would break all pre-existing instances? Should we save all old passwords, which are still in effect?
Should we go back, and fix up the old instances when the password changes? Warn the Admin, and not allow the password to be changed?
--
CraigMeyer - 2010-12-05
Should the Admin always have access to the clear text?
--
CraigMeyer - 2010-12-05
I would not worry about users duplicating an ENCRYPT with
_dont_change meta hash key, this can be an undefined state.
How about adding some salt when building the meta hash key? This would avoid having the same meta hash key with identical to-encrypt-text.
If you feel the Blowfish is good enough there is may be no need for RC4?
I do not understand, why is the admin password needed? Possibly do with a separate password just for this plugin?
People in the TWikiAdminGroup are considered root users, e.g. they can have access to all content.
No issue if the plugin does not show the clear text to the admin in case not in the group specified. The admin could edit the group and add himself/herself anyway. It might be better not to show the admin the clear text, so that it is an explicit step to gain access.
--
PeterThoeny - 2010-12-05
Actually the
index is effectively repeatable salt.
In the afterEditHandler(), the code recomputes the hash, to make sure the
_dont_change parameter wasn't modified. The hash is computed with the:
clear_text + index + allow and then RSA signed, and md6 hashed.
My concern about Admin's changing password wasn't stated clearly. I am concerned, that people will use the plugin, encrypt useful information. Then the TWiki decides to change the internal password for
EncryptPlugin, for some reason. (Ex: Some Corporations have a policy of 90 day password changing.)
Once the
EncryptPlugin internal password is changed, all the previously encrypted content is lost. This is my concern. We should warn the TWiki Admin, that previous encrypted content will be lost.
--
CraigMeyer - 2010-12-06
Just curious, why do you need the index as a parameter in the meta data? If
_dont_change is computed to be unique is there a need for it? OK if user reorders the ENCRYPT variables in the page?
Ah, yes, makes sense on password change. Warning admin is good for first implementation.
I recommend to create a
Config.spec so that admins can easily configure the the plugin using
configure, including explanation such as password change warning. See example
SVN:GoogleAnalyticsPlugin/lib/TWiki/Plugins/GoogleAnalyticsPlugin/Config.spec
--
PeterThoeny - 2010-12-06