reorganized cyrus sasl plugin

svn path=/trunk/kdesupport/qca/; revision=245831
This commit is contained in:
Justin Karneges 2003-08-28 01:38:28 +00:00
parent 72be06386a
commit 1a0cf2b8e5
5 changed files with 326 additions and 183 deletions

7
TODO
View File

@ -1,14 +1,11 @@
* cipher: option to specify size for genkey * cipher: option to specify size for genkey
* cert: properly check hostnames with wildcards * cert: properly check hostnames with wildcards
* ssl: error signal * ssl: error signal
* sasl: option to not support client-send-first * sasl: bring API up to speed with the plugin
* sasl: other security options
* sasl: server auth callback
* sasl: security layer
* openssl plugin: fixmes and todos * openssl plugin: fixmes and todos
* cyrussasl plugin: serverstepthread
* sasl: external auth
* dsa * dsa
* diffie-hellman * diffie-hellman

View File

@ -29,6 +29,7 @@ extern "C"
#include<qstringlist.h> #include<qstringlist.h>
#include<qptrlist.h> #include<qptrlist.h>
#include<qfile.h> #include<qfile.h>
#include<qthread.h>
#define SASL_BUFSIZE 8192 #define SASL_BUFSIZE 8192
@ -185,10 +186,25 @@ static QString methodsToString(const QStringList &methods)
return list; return list;
} }
// needed to give interactive behavior to a callback-based function
class ServerStepThread : public QThread
{
public:
ServerStepThread()
{
}
void run()
{
//int r = sasl_server_start(con, in_mech.latin1(), clientin, clientinlen, &serverout, &serveroutlen);
}
};
class SASLContext : public QCA_SASLContext class SASLContext : public QCA_SASLContext
{ {
public: public:
QCACyrusSASL *g; QCACyrusSASL *g;
ServerStepThread *sst;
// core props // core props
QString service, host; QString service, host;
@ -197,25 +213,37 @@ public:
// security props // security props
int secflags; int secflags;
int ssf_min, ssf_max; int ssf_min, ssf_max;
QString ext_authid;
// params int ext_ssf;
SASLParams params;
int ssf, maxoutbuf;
sasl_conn_t *con; sasl_conn_t *con;
sasl_interact_t *need; sasl_interact_t *need;
int ssf, maxoutbuf;
QStringList mechlist; QStringList mechlist;
bool servermode;
sasl_callback_t *callbacks; sasl_callback_t *callbacks;
bool (*authCallback)(const QString &authname, const QString &username, QCA_SASLContext *c);
// state
bool servermode;
int step;
bool in_sendFirst;
QByteArray in_buf;
QString in_mech;
bool in_useClientInit;
QByteArray in_clientInit;
QString out_mech;
bool out_useClientInit;
QByteArray out_clientInit;
QByteArray out_buf;
SASLParams params;
QString sc_authname, sc_username;
SASLContext(QCACyrusSASL *_g) SASLContext(QCACyrusSASL *_g)
{ {
g = _g; g = _g;
con = 0; con = 0;
need = 0;
callbacks = 0; callbacks = 0;
authCallback = 0; sst = 0;
reset(); reset();
} }
@ -233,6 +261,10 @@ public:
void resetState() void resetState()
{ {
if(sst) {
// only would happen if the user forgot to call setAuth, so let's do it now
setAuth(false);
}
if(con) { if(con) {
sasl_dispose(&con); sasl_dispose(&con);
con = 0; con = 0;
@ -248,6 +280,8 @@ public:
mechlist.clear(); mechlist.clear();
ssf = 0; ssf = 0;
maxoutbuf = 0; maxoutbuf = 0;
sc_authname = "";
sc_username = "";
} }
void resetParams() void resetParams()
@ -256,6 +290,8 @@ public:
secflags = 0; secflags = 0;
ssf_min = 0; ssf_min = 0;
ssf_max = 0; ssf_max = 0;
ext_authid = "";
ext_ssf = 0;
} }
void setCoreProps(const QString &_service, const QString &_host, QCA_SASLHostPort *la, QCA_SASLHostPort *ra) void setCoreProps(const QString &_service, const QString &_host, QCA_SASLHostPort *la, QCA_SASLHostPort *ra)
@ -266,7 +302,7 @@ public:
remoteAddr = ra ? addrString(*ra) : ""; remoteAddr = ra ? addrString(*ra) : "";
} }
void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax) void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax, const QString &_ext_authid, int _ext_ssf)
{ {
int sf = 0; int sf = 0;
if(noPlain) if(noPlain)
@ -286,11 +322,8 @@ public:
secflags = sf; secflags = sf;
ssf_min = ssfMin; ssf_min = ssfMin;
ssf_max = ssfMax; ssf_max = ssfMax;
} ext_authid = _ext_authid;
ext_ssf = _ext_ssf;
void setAuthCallback(bool (*auth)(const QString &authname, const QString &username, QCA_SASLContext *c))
{
authCallback = auth;
} }
static int scb_checkauth(sasl_conn_t *, void *context, const char *requested_user, unsigned, const char *auth_identity, unsigned, const char *, unsigned, struct propctx *) static int scb_checkauth(sasl_conn_t *, void *context, const char *requested_user, unsigned, const char *auth_identity, unsigned, const char *, unsigned, struct propctx *)
@ -298,17 +331,17 @@ public:
SASLContext *that = (SASLContext *)context; SASLContext *that = (SASLContext *)context;
QString authname = auth_identity; QString authname = auth_identity;
QString username = requested_user; QString username = requested_user;
if(that->authCallback) { /*if(that->authCallback) {
if(that->authCallback(authname, username, that)) if(that->authCallback(authname, username, that))
return SASL_OK; return SASL_OK;
else else
return SASL_NOAUTHZ; return SASL_NOAUTHZ;
} }
else else*/
return SASL_OK; return SASL_OK;
} }
void setsecprops() bool setsecprops()
{ {
sasl_security_properties_t secprops; sasl_security_properties_t secprops;
secprops.min_ssf = ssf_min; secprops.min_ssf = ssf_min;
@ -317,7 +350,22 @@ public:
secprops.property_names = NULL; secprops.property_names = NULL;
secprops.property_values = NULL; secprops.property_values = NULL;
secprops.security_flags = secflags; secprops.security_flags = secflags;
sasl_setprop(con, SASL_SEC_PROPS, &secprops); int r = sasl_setprop(con, SASL_SEC_PROPS, &secprops);
if(r != SASL_OK)
return false;
if(!ext_authid.isEmpty()) {
const char *authid = ext_authid.latin1();
sasl_ssf_t ssf = ext_ssf;
r = sasl_setprop(con, SASL_SSF_EXTERNAL, &ssf);
if(r != SASL_OK)
return false;
r = sasl_setprop(con, SASL_AUTH_EXTERNAL, &authid);
if(r != SASL_OK)
return false;
}
return true;
} }
void getssfparams() void getssfparams()
@ -369,13 +417,21 @@ public:
if(r != SASL_OK) if(r != SASL_OK)
return false; return false;
setsecprops(); if(!setsecprops())
return false;
mechlist = _mechlist; mechlist = _mechlist;
servermode = false; servermode = false;
step = 0;
return true; return true;
} }
int clientFirstStep(bool allowClientSendFirst)
{
in_sendFirst = allowClientSendFirst;
return clientTryAgain();
}
bool serverStart(const QString &realm, QStringList *mechlist, const QString &name) bool serverStart(const QString &realm, QStringList *mechlist, const QString &name)
{ {
resetState(); resetState();
@ -400,7 +456,8 @@ public:
if(r != SASL_OK) if(r != SASL_OK)
return false; return false;
setsecprops(); if(!setsecprops())
return false;
const char *ml; const char *ml;
r = sasl_listmech(con, 0, NULL, " ", NULL, &ml, 0, 0); r = sasl_listmech(con, 0, NULL, " ", NULL, &ml, 0, 0);
@ -408,138 +465,201 @@ public:
return false; return false;
*mechlist = QStringList::split(' ', ml); *mechlist = QStringList::split(' ', ml);
servermode = true; servermode = true;
step = 0;
return true; return true;
} }
int clientFirstStep(QString *mech, QByteArray **out, QCA_SASLNeedParams *np) int serverFirstStep(const QString &mech, const QByteArray *in)
{ {
bool supportClientSendFirst = out ? true: false; in_mech = mech;
const char *clientout, *m;
unsigned int clientoutlen;
need = 0;
QString list = methodsToString(mechlist);
int r;
while(1) {
if(need)
params.extractHave(need);
if(supportClientSendFirst)
r = sasl_client_start(con, list.latin1(), &need, &clientout, &clientoutlen, &m);
else
r = sasl_client_start(con, list.latin1(), &need, NULL, NULL, &m);
if(r != SASL_INTERACT)
break;
params.applyInteract(need);
if(params.missingAny()) {
*np = params.need;
return NeedParams;
}
}
if(r != SASL_OK && r != SASL_CONTINUE)
return Error;
*mech = m;
if(supportClientSendFirst && clientout)
*out = new QByteArray(makeByteArray(clientout, clientoutlen));
else
*out = 0;
if(r == SASL_OK) {
getssfparams();
return Success;
}
else
return Continue;
}
int serverFirstStep(const QString &mech, const QByteArray *in, QByteArray *out)
{
const char *clientin = 0;
unsigned int clientinlen = 0;
if(in) { if(in) {
clientin = in->data(); in_useClientInit = true;
clientinlen = in->size(); in_clientInit = in->copy();
}
const char *serverout;
unsigned int serveroutlen;
int r = sasl_server_start(con, mech.latin1(), clientin, clientinlen, &serverout, &serveroutlen);
if(r != SASL_OK && r != SASL_CONTINUE)
return Error;
*out = makeByteArray(serverout, serveroutlen);
if(r == SASL_OK) {
getssfparams();
return Success;
} }
else else
return Continue; in_useClientInit = false;
return serverTryAgain();
} }
int clientNextStep(const QByteArray &in, QByteArray *out, QCA_SASLNeedParams *np) QCA_SASLNeedParams clientParamsNeeded() const
{ {
//clearNeedParams(np); return params.need;
const char *clientout; }
unsigned int clientoutlen;
int r;
while(1) {
if(need)
params.extractHave(need);
r = sasl_client_step(con, in.data(), in.size(), &need, &clientout, &clientoutlen);
if(r != SASL_INTERACT)
break;
params.applyInteract(need); void setClientParams(const QString *auth, const QString *user, const QString *pass, const QString *realm)
if(params.missingAny()) { {
*np = params.need; if(auth)
return NeedParams; params.setAuthname(*auth);
if(user)
params.setUsername(*user);
if(pass)
params.setPassword(*pass);
if(realm)
params.setRealm(*realm);
}
QString authname() const
{
return sc_authname;
}
QString username() const
{
return sc_username;
}
void setAuth(bool)
{
if(!sst)
return;
// TODO: send the decision to the thread
sst->wait();
delete sst;
sst = 0;
}
int nextStep(const QByteArray &in)
{
in_buf = in.copy();
return tryAgain();
}
int tryAgain()
{
if(servermode)
return serverTryAgain();
else
return clientTryAgain();
}
QString mech() const
{
return out_mech;
}
const QByteArray *clientInit() const
{
if(out_useClientInit)
return &out_clientInit;
else
return 0;
}
QByteArray result() const
{
return out_buf;
}
int clientTryAgain()
{
if(step == 0) {
const char *clientout, *m;
unsigned int clientoutlen;
need = 0;
QString list = methodsToString(mechlist);
int r;
while(1) {
if(need)
params.extractHave(need);
if(in_sendFirst)
r = sasl_client_start(con, list.latin1(), &need, &clientout, &clientoutlen, &m);
else
r = sasl_client_start(con, list.latin1(), &need, NULL, NULL, &m);
if(r != SASL_INTERACT)
break;
params.applyInteract(need);
if(params.missingAny())
return NeedParams;
} }
if(r != SASL_OK && r != SASL_CONTINUE)
return Error;
out_mech = m;
if(in_sendFirst && clientout) {
out_clientInit = makeByteArray(clientout, clientoutlen);
out_useClientInit = true;
}
else
out_useClientInit = false;
++step;
if(r == SASL_OK) {
getssfparams();
return Success;
}
else
return Continue;
} }
if(r != SASL_OK && r != SASL_CONTINUE) else {
return Error; const char *clientout;
*out = makeByteArray(clientout, clientoutlen); unsigned int clientoutlen;
if(r == SASL_OK) { int r;
getssfparams(); while(1) {
return Success; if(need)
params.extractHave(need);
r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen);
if(r != SASL_INTERACT)
break;
params.applyInteract(need);
if(params.missingAny())
return NeedParams;
}
if(r != SASL_OK && r != SASL_CONTINUE)
return Error;
out_buf = makeByteArray(clientout, clientoutlen);
if(r == SASL_OK) {
getssfparams();
return Success;
}
else
return Continue;
} }
else }
int serverTryAgain()
{
if(step == 0) {
const char *clientin = 0;
unsigned int clientinlen = 0;
if(in_useClientInit) {
clientin = in_clientInit.data();
clientinlen = in_clientInit.size();
}
const char *serverout;
unsigned int serveroutlen;
int r = sasl_server_start(con, in_mech.latin1(), clientin, clientinlen, &serverout, &serveroutlen);
if(r != SASL_OK && r != SASL_CONTINUE)
return Error;
out_buf = makeByteArray(serverout, serveroutlen);
++step;
if(r == SASL_OK) {
getssfparams();
return Success;
}
else
return Continue;
}
else {
const char *serverout;
unsigned int serveroutlen;
int r = sasl_server_step(con, in_buf.data(), in_buf.size(), &serverout, &serveroutlen);
if(r != SASL_OK && r != SASL_CONTINUE)
return Error;
if(r == SASL_OK) {
out_buf.resize(0);
getssfparams();
return Success;
}
out_buf = makeByteArray(serverout, serveroutlen);
return Continue; return Continue;
}
int serverNextStep(const QByteArray &in, QByteArray *out)
{
const char *serverout;
unsigned int serveroutlen;
int r = sasl_server_step(con, in.data(), in.size(), &serverout, &serveroutlen);
if(r != SASL_OK && r != SASL_CONTINUE)
return Error;
if(r == SASL_OK) {
out->resize(0);
getssfparams();
return Success;
} }
*out = makeByteArray(serverout, serveroutlen);
return Continue;
}
void setAuthname(const QString &s)
{
params.setAuthname(s);
}
void setUsername(const QString &s)
{
params.setUsername(s);
}
void setPassword(const QString &s)
{
params.setPassword(s);
}
void setRealm(const QString &s)
{
params.setRealm(s);
} }
bool encode(const QByteArray &in, QByteArray *out) bool encode(const QByteArray &in, QByteArray *out)

View File

@ -837,6 +837,7 @@ public:
delete c; delete c;
} }
bool tried;
QCA_SASLContext *c; QCA_SASLContext *c;
bool allowPlain; bool allowPlain;
QHostAddress localAddr, remoteAddr; QHostAddress localAddr, remoteAddr;
@ -897,11 +898,12 @@ bool SASL::startClient(const QString &service, const QString &host, const QStrin
} }
d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0); d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
d->c->setSecurityProps(!d->allowPlain, false, false, false, false, false, false, 0, 256); d->c->setSecurityProps(!d->allowPlain, false, false, false, false, false, false, 0, 256, "", 0);
if(!d->c->clientStart(mechlist)) if(!d->c->clientStart(mechlist))
return false; return false;
d->first = true; d->first = true;
d->server = false; d->server = false;
d->tried = false;
QTimer::singleShot(0, this, SLOT(tryAgain())); QTimer::singleShot(0, this, SLOT(tryAgain()));
return true; return true;
} }
@ -919,34 +921,33 @@ bool SASL::startServer(const QString &service, const QString &host, const QStrin
} }
d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0); d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
d->c->setSecurityProps(!d->allowPlain, false, false, false, false, false, false, 0, 256); d->c->setSecurityProps(!d->allowPlain, false, false, false, false, false, false, 0, 256, "", 0);
if(!d->c->serverStart(realm, mechlist, saslappname)) if(!d->c->serverStart(realm, mechlist, saslappname))
return false; return false;
d->first = true; d->first = true;
d->server = true; d->server = true;
d->tried = false;
return true; return true;
} }
void SASL::putServerFirstStep(const QString &mech) void SASL::putServerFirstStep(const QString &mech)
{ {
QByteArray buf; int r = d->c->serverFirstStep(mech, 0);
int r = d->c->serverFirstStep(mech, 0, &buf); handleServerFirstStep(r);
handleServerFirstStep(r, buf);
} }
void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit) void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit)
{ {
QByteArray buf; int r = d->c->serverFirstStep(mech, &clientInit);
int r = d->c->serverFirstStep(mech, &clientInit, &buf); handleServerFirstStep(r);
handleServerFirstStep(r, buf);
} }
void SASL::handleServerFirstStep(int r, const QByteArray &buf) void SASL::handleServerFirstStep(int r)
{ {
if(r == QCA_SASLContext::Success) if(r == QCA_SASLContext::Success)
authenticated(true); authenticated(true);
else if(r == QCA_SASLContext::Continue) else if(r == QCA_SASLContext::Continue)
nextStep(buf); nextStep(d->c->result());
else else
authenticated(false); authenticated(false);
} }
@ -959,22 +960,22 @@ void SASL::putStep(const QByteArray &stepData)
void SASL::setAuthname(const QString &auth) void SASL::setAuthname(const QString &auth)
{ {
d->c->setAuthname(auth); d->c->setClientParams(&auth, 0, 0, 0);
} }
void SASL::setUsername(const QString &user) void SASL::setUsername(const QString &user)
{ {
d->c->setUsername(user); d->c->setClientParams(0, &user, 0, 0);
} }
void SASL::setPassword(const QString &pass) void SASL::setPassword(const QString &pass)
{ {
d->c->setPassword(pass); d->c->setClientParams(0, 0, &pass, 0);
} }
void SASL::setRealm(const QString &realm) void SASL::setRealm(const QString &realm)
{ {
d->c->setRealm(realm); d->c->setClientParams(0, 0, 0, &realm);
} }
void SASL::continueAfterParams() void SASL::continueAfterParams()
@ -987,50 +988,70 @@ void SASL::tryAgain()
int r; int r;
if(d->server) { if(d->server) {
QByteArray out; if(!d->tried) {
r = d->c->serverNextStep(d->stepData, &out); r = d->c->nextStep(d->stepData);
d->tried = true;
}
else
r = d->c->tryAgain();
if(r == QCA_SASLContext::Error) { if(r == QCA_SASLContext::Error) {
authenticated(false); authenticated(false);
return; return;
} }
else if(r == QCA_SASLContext::Continue) { else if(r == QCA_SASLContext::Continue) {
nextStep(out); d->tried = false;
nextStep(d->c->result());
return; return;
} }
} }
else { else {
if(d->first) { if(d->first) {
QString mech; if(!d->tried) {
QByteArray *clientInit; r = d->c->clientFirstStep(true);
QCA_SASLNeedParams np; d->tried = true;
r = d->c->clientFirstStep(&mech, &clientInit, &np); }
else
r = d->c->tryAgain();
if(r == QCA_SASLContext::Error) { if(r == QCA_SASLContext::Error) {
authenticated(false); authenticated(false);
return; return;
} }
else if(r == QCA_SASLContext::NeedParams) { else if(r == QCA_SASLContext::NeedParams) {
d->tried = false;
QCA_SASLNeedParams np = d->c->clientParamsNeeded();
needParams(np.auth, np.user, np.pass, np.realm); needParams(np.auth, np.user, np.pass, np.realm);
return; return;
} }
QString mech = d->c->mech();
const QByteArray *clientInit = d->c->clientInit();
d->first = false; d->first = false;
d->tried = false;
clientFirstStep(mech, clientInit); clientFirstStep(mech, clientInit);
delete clientInit;
} }
else { else {
QByteArray out; if(!d->tried) {
QCA_SASLNeedParams np; r = d->c->nextStep(d->stepData);
r = d->c->clientNextStep(d->stepData, &out, &np); d->tried = true;
}
else
r = d->c->tryAgain();
if(r == QCA_SASLContext::Error) { if(r == QCA_SASLContext::Error) {
authenticated(false); authenticated(false);
return; return;
} }
else if(r == QCA_SASLContext::NeedParams) { else if(r == QCA_SASLContext::NeedParams) {
d->tried = false;
QCA_SASLNeedParams np = d->c->clientParamsNeeded();
needParams(np.auth, np.user, np.pass, np.realm); needParams(np.auth, np.user, np.pass, np.realm);
return; return;
} }
//else if(r == QCA_SASLContext::Continue) { //else if(r == QCA_SASLContext::Continue) {
nextStep(out); nextStep(d->c->result());
// return; // return;
//} //}
} }

View File

@ -372,7 +372,7 @@ namespace QCA
class Private; class Private;
Private *d; Private *d;
void handleServerFirstStep(int r, const QByteArray &buf); void handleServerFirstStep(int r);
}; };
}; };

View File

@ -134,31 +134,36 @@ struct QCA_SASLNeedParams
class QCA_SASLContext class QCA_SASLContext
{ {
public: public:
enum { Success, Error, NeedParams, Continue }; enum { Success, Error, NeedParams, AuthCheck, Continue };
virtual ~QCA_SASLContext() {} virtual ~QCA_SASLContext() {}
// common // common
virtual void reset()=0; virtual void reset()=0;
virtual void setCoreProps(const QString &service, const QString &host, QCA_SASLHostPort *local, QCA_SASLHostPort *remote)=0; virtual void setCoreProps(const QString &service, const QString &host, QCA_SASLHostPort *local, QCA_SASLHostPort *remote)=0;
virtual void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax)=0; virtual void setSecurityProps(bool noPlain, bool noActive, bool noDict, bool noAnon, bool reqForward, bool reqCreds, bool reqMutual, int ssfMin, int ssfMax, const QString &_ext_authid, int _ext_ssf)=0;
virtual int security() const=0; virtual int security() const=0;
// client // init / first step
virtual bool clientStart(const QStringList &mechlist)=0; virtual bool clientStart(const QStringList &mechlist)=0;
virtual int clientFirstStep(QString *mech, QByteArray **out, QCA_SASLNeedParams *np)=0; virtual int clientFirstStep(bool allowClientSendFirst)=0;
virtual int clientNextStep(const QByteArray &in, QByteArray *out, QCA_SASLNeedParams *np)=0;
// server
virtual bool serverStart(const QString &realm, QStringList *mechlist, const QString &name)=0; virtual bool serverStart(const QString &realm, QStringList *mechlist, const QString &name)=0;
virtual int serverFirstStep(const QString &mech, const QByteArray *in, QByteArray *out)=0; virtual int serverFirstStep(const QString &mech, const QByteArray *in)=0;
virtual int serverNextStep(const QByteArray &in, QByteArray *out)=0;
virtual void setAuthCallback(bool (*auth)(const QString &authname, const QString &username, QCA_SASLContext *c))=0;
// client params // get / set params
virtual void setAuthname(const QString &)=0; virtual QCA_SASLNeedParams clientParamsNeeded() const=0;
virtual void setUsername(const QString &)=0; virtual void setClientParams(const QString *auth, const QString *user, const QString *pass, const QString *realm)=0;
virtual void setPassword(const QString &)=0; virtual QString authname() const=0;
virtual void setRealm(const QString &)=0; virtual QString username() const=0;
virtual void setAuth(bool)=0;
// continue steps
virtual int nextStep(const QByteArray &in)=0;
virtual int tryAgain()=0;
// results
virtual QString mech() const=0;
virtual const QByteArray *clientInit() const=0;
virtual QByteArray result() const=0;
// security layer // security layer
virtual bool encode(const QByteArray &in, QByteArray *out)=0; virtual bool encode(const QByteArray &in, QByteArray *out)=0;