Encrypt communication with plugins
[accounts-sso:signon.git] / lib / plugins / signon-plugins-common / SignOn / encrypteddevice.cpp
1 /*
2  * This file is part of signon
3  *
4  * Copyright (C) 2009-2011 Nokia Corporation.
5  *
6  * Contact: Rauli Ikonen <rauli.ikonen@nixuopen.org>
7  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * version 2.1 as published by the Free Software Foundation.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23
24 #include "encrypteddevice.h"
25
26 #include <openssl/err.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 #include "SignOn/signonplugincommon.h"
31
32 using namespace SignOn;
33
34 EncryptedDevice::EncryptedDevice(QIODevice *actualDevice,
35                                  const unsigned char *encryptionKey,
36                                  unsigned int keySize,
37                                  const unsigned char *ivIn,
38                                  const unsigned char *ivOut):
39     m_actualDevice(actualDevice),
40     m_currentPosOut(0),
41     m_currentPosIn(0),
42     m_tempByteArray(NULL),
43     m_tempByteArrayPos(0),
44     m_valid(true)
45 {
46     setOpenMode(actualDevice->openMode());
47
48     if (AES_set_encrypt_key(encryptionKey, keySize * 8,
49                             &m_encryptionKey) != 0) {
50         BLAME() << "AES_set_encrypt_key failed:" << ERR_get_error();
51         m_valid = false;
52         return;
53     }
54
55     AES_ecb_encrypt(ivOut, m_keyStreamOut, &m_encryptionKey, AES_ENCRYPT);
56     AES_ecb_encrypt(ivIn, m_keyStreamIn, &m_encryptionKey, AES_ENCRYPT);
57 }
58
59 bool EncryptedDevice::open(OpenMode mode)
60 {
61     if (!m_valid)
62         return false;
63     if (!m_actualDevice->open(mode))
64         return false;
65     return QIODevice::open(mode);
66 }
67
68 void EncryptedDevice::close()
69 {
70     m_actualDevice->close();
71     QIODevice::close();
72 }
73
74 qint64 EncryptedDevice::bytesAvailable() const
75 {
76     if (m_tempByteArray != NULL)
77         return m_tempByteArray->size() - m_tempByteArrayPos;
78     return m_actualDevice->bytesAvailable();
79 }
80
81 qint64 EncryptedDevice::bytesToWrite() const
82 {
83     return m_actualDevice->bytesToWrite();
84 }
85
86 qint64 EncryptedDevice::readData(char *data, qint64 maxLen)
87 {
88     qint64 bytesRead = 0;
89     if (m_tempByteArray != NULL) {
90         if (m_tempByteArrayPos < m_tempByteArray->size()) {
91             int bytesToRead = m_tempByteArray->size() - m_tempByteArrayPos;
92             if (bytesToRead > maxLen)
93                 bytesToRead = (int)maxLen;
94             memcpy(data, m_tempByteArray->constData(), bytesToRead);
95             bytesRead = bytesToRead;
96             m_tempByteArrayPos += bytesToRead;
97         }
98     } else {
99         bytesRead = m_actualDevice->read(data, maxLen);
100     }
101
102     for (qint64 i = 0; i < bytesRead; ++i) {
103         if (m_currentPosIn == AES_BLOCK_SIZE) {
104             AES_ecb_encrypt(m_keyStreamIn, m_keyStreamIn,
105                             &m_encryptionKey, AES_ENCRYPT);
106             m_currentPosIn = 0;
107         }
108         data[i] = data[i] ^ m_keyStreamIn[m_currentPosIn];
109         ++m_currentPosIn;
110     }
111
112     return bytesRead;
113 }
114
115 qint64 EncryptedDevice::writeData(const char *data, qint64 len)
116 {
117     if (len <= 0)
118         return 0;
119
120     char *encryptedData = (char *)malloc(len);
121     if (encryptedData == NULL)
122         return -1;
123
124     for (qint64 i = 0; i < len; ++i) {
125         if (m_currentPosOut == AES_BLOCK_SIZE) {
126             AES_ecb_encrypt(m_keyStreamOut, m_keyStreamOut,
127                             &m_encryptionKey, AES_ENCRYPT);
128             m_currentPosOut = 0;
129         }
130         encryptedData[i] = data[i] ^ m_keyStreamOut[m_currentPosOut];
131         ++m_currentPosOut;
132     }
133
134     qint64 totalBytesWritten = 0;
135     while (totalBytesWritten < len) {
136         qint64 bytesWritten =
137                 m_actualDevice->write(encryptedData + totalBytesWritten,
138                                       len - totalBytesWritten);
139         if (bytesWritten < 0)
140             break;
141         totalBytesWritten += bytesWritten;
142     }
143     free(encryptedData);
144
145     return totalBytesWritten;
146 }