Index: trunk/lib/Vote/DB/Poll.pm
===================================================================
--- trunk/lib/Vote/DB/Poll.pm	(revision 173)
+++ trunk/lib/Vote/DB/Poll.pm	(revision 175)
@@ -8,4 +8,6 @@
 use Mail::Mailer;
 use Crypt::RSA;
+use Crypt::RSA::Key::Public::SSH;
+use Crypt::RSA::Key::Private::SSH;
 use Crypt::CBC;
 use XML::Simple;
@@ -37,4 +39,12 @@
 
 sub voteid { $_[0]->{voteid} }
+
+sub setup {
+    my ($self) = @_;
+    $self->param(
+        free_choice => 0,
+        choice_count => 1,
+    );
+}
 
 sub param {
@@ -294,4 +304,18 @@
     my ($self, $choice, $fchoice) = @_;
 
+    my $uid = ($self->is_crypted
+        ? $self->_register_ballot_crypted($choice, $fchoice)
+        : $self->_register_ballot_clear($choice, $fchoice))
+        or do {
+            self->db->rollback;
+            return;
+        };
+
+    $uid
+}
+
+sub _register_ballot_clear {
+    my ($self, $choice, $fchoice, $uid) = @_;
+
     my $addb = $self->db->prepare_cached(
         q{
@@ -299,5 +323,5 @@
         }
     );
-    my $uid = Vote::DB::common::gen_uid();
+    $uid ||= Vote::DB::common::gen_uid();
     $addb->execute($uid, $self->voteid, scalar(@{$fchoice || []}) ? undef : 'f') or do {
         self->db->rollback;
@@ -336,4 +360,68 @@
 
     $uid;
+}
+
+sub _register_ballot_crypted {
+    my ($self, $choice, $fchoice) = @_;
+    my $xml = XML::Simple->new(ForceArray => 1, RootName => 'ballot');
+    my $symkey = map{ chr(rand(256)) } (1 .. (256 / 8));
+    my $cipher = new Crypt::CBC($symkey, 'DES');
+    my $ballotuid = Vote::DB::common::gen_uid();
+    my $encryptedballot = $cipher->encrypt_hex(
+        $xml->XMLout({
+            id => $ballotuid,
+            sbal => $choice,
+            fsbal => $fchoice
+        })
+    );
+    my $encsymkey = $self->rsa->encrypt (
+        Message    => $symkey,
+        Key        => $self->public_key,
+        Armour     => 1,
+    ) || die $self->rsa->errstr();
+
+    my $addenc = $self->db->prepare_cached(
+        q{insert into ballot_enc (id, data, enckey, poll) values (?,?,?,?)}
+    );
+
+    my $uid = Vote::DB::common::gen_uid();
+    $addenc->execute($uid, $encryptedballot, $encsymkey, $self->voteid);
+    $ballotuid;
+}
+
+sub _decrypted_ballot {
+    my ($self, $ballotid, $privkey) = @_;
+    my $sth = $self->db->prepare_cached(
+        q{select * from ballot_enc where id = ? for update}
+    );
+    $sth->execute($ballotid);
+    my $ballot = $sth->fetchrow_hashref;
+    $sth->finish;
+    my $encsymkey = $ballot->{enckey};
+    my $data = $ballot->{data};
+    my $symkey = $self->rsa->decrypt (
+        Cyphertext => $encsymkey,
+        Key        => $privkey,
+        Armour     => 1,
+    ) || die $self->rsa->errstr();
+    my $cipher = new Crypt::CBC($symkey, 'DES');
+    my $xmldata = XMLin($cipher->decrypt_hex($data), ForceArray => 1);
+    $self->_register_ballot_clear($xmldata->{sbal}, $xmldata->{fsbal}, $xmldata->{id});
+    my $upd = $self->db->prepare_cached(q{update ballot_enc set decrypted = true where id = ?});
+    if ($upd->execute($ballotid)) {
+        $self->db->commit;
+        return;
+    } else {
+        $self->db->rollback;
+        return 1;
+    }
+}    
+
+sub decrypted_ballots {
+    my ($self, $password) = @_;
+    my $privkey = $self->private_key($password);
+    foreach ($self->list_ballot_need_dec) {
+        $self->_decrypted_ballot($_, $privkey);
+    }
 }
 
@@ -422,11 +510,34 @@
 }
 
+sub is_crypted {
+    my ($self) = @_;
+    return $self->info->{public_key} ? 1 : 0;
+}
+
 sub ballot_count {
     my ($self) = @_;
-
-    my $sth = $self->db->prepare_cached(
-        q{
-        select count(*) from ballot where poll = ?
-        }
+    return $self->is_crypted
+        ? $self->ballot_count_crypt
+        : $self->ballot_count_clear;
+}
+
+sub ballot_count_clear {
+    my ($self) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{select count(*) from ballot where poll = ?}
+    );
+
+    $sth->execute($self->voteid);
+    my $res = $sth->fetchrow_hashref;
+    $sth->finish;
+    $res->{count}
+}
+
+sub ballot_count_crypt {
+    my ($self) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{select count(*) from ballot_enc where poll = ?}
     );
 
@@ -565,4 +676,38 @@
         q{
         select id from ballot where poll = ?
+        order by id
+        }
+    );
+    $sth->execute($self->voteid);
+    my @ids;
+    while (my $res = $sth->fetchrow_hashref) {
+        push(@ids, $res->{id});
+    }
+    @ids
+}
+
+sub list_ballot_enc {
+    my ($self) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{
+        select id from ballot_enc where poll = ?
+        order by id
+        }
+    );
+    $sth->execute($self->voteid);
+    my @ids;
+    while (my $res = $sth->fetchrow_hashref) {
+        push(@ids, $res->{id});
+    }
+    @ids
+}
+
+sub list_ballot_need_dec {
+    my ($self) = @_;
+
+    my $sth = $self->db->prepare_cached(
+        q{
+        select id from ballot_enc where poll = ? and decrypted = 'false'
         order by id
         }
@@ -715,9 +860,9 @@
 
 sub gen_poll_keys {
-    my ($self) = @_;
+    my ($self, $password) = @_;
     my ($public, $private) = $self->rsa->keygen (
         Identity  => 'Epoll Vote ' . $self->voteid,
         Size      => 768,
-        Password  => undef,
+        Password  => $password,
         Verbosity => 0,
         KF=>'SSH',
@@ -732,10 +877,16 @@
     my ($self) = @_;
     my $serialize = $self->info->{public_key} or return;
-    my $pubkey = Crypt::RSA::Key::Public->new;
-    $pubkey->deserialize($serialize);
-
+    my $pubkey = Crypt::RSA::Key::Public::SSH->new;
+    $pubkey->deserialize(String => [ $serialize ]);
     $pubkey
 }
 
+sub private_key {
+    my ($self, $password) = @_;
+    my $serialize = $self->info->{private_key} or return;
+    my $privkey = Crypt::RSA::Key::Private::SSH->new;
+    $privkey->deserialize(String => [ decode_base64($serialize) ], Passphrase => $password);
+    $privkey
+}
 =head1 AUTHOR
 
