2019-09-10 18:55:24 +00:00
|
|
|
using GLib;
|
|
|
|
|
|
|
|
namespace Crypto {
|
|
|
|
public abstract class SymmetricCipherConverter : Converter, Object {
|
|
|
|
internal SymmetricCipher cipher;
|
|
|
|
internal size_t attached_taglen;
|
|
|
|
|
|
|
|
public abstract ConverterResult convert(uint8[] inbuf, uint8[] outbuf, ConverterFlags flags, out size_t bytes_read, out size_t bytes_written) throws IOError;
|
|
|
|
|
|
|
|
public uint8[] get_tag(size_t taglen) throws Error {
|
|
|
|
return cipher.get_tag(taglen);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void check_tag(uint8[] tag) throws Error {
|
|
|
|
cipher.check_tag(tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void reset() {
|
2019-09-16 21:47:38 +00:00
|
|
|
try {
|
|
|
|
cipher.reset();
|
|
|
|
} catch (Crypto.Error e) {
|
|
|
|
warning(@"$(e.domain) error while resetting cipher: $(e.message)");
|
|
|
|
}
|
2019-09-10 18:55:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class SymmetricCipherEncrypter : SymmetricCipherConverter {
|
|
|
|
public SymmetricCipherEncrypter(owned SymmetricCipher cipher, size_t attached_taglen = 0) {
|
|
|
|
this.cipher = (owned) cipher;
|
|
|
|
this.attached_taglen = attached_taglen;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override ConverterResult convert(uint8[] inbuf, uint8[] outbuf, ConverterFlags flags, out size_t bytes_read, out size_t bytes_written) throws IOError {
|
|
|
|
if (inbuf.length > outbuf.length) {
|
|
|
|
throw new IOError.NO_SPACE("CipherConverter needs at least the size of input as output space");
|
|
|
|
}
|
|
|
|
if ((flags & ConverterFlags.INPUT_AT_END) != 0 && inbuf.length + attached_taglen > outbuf.length) {
|
|
|
|
throw new IOError.NO_SPACE("CipherConverter needs additional output space to attach tag");
|
|
|
|
}
|
2019-09-16 21:47:38 +00:00
|
|
|
try {
|
|
|
|
if (inbuf.length > 0) {
|
|
|
|
cipher.encrypt(outbuf, inbuf);
|
2019-09-10 18:55:24 +00:00
|
|
|
}
|
2019-09-16 21:47:38 +00:00
|
|
|
bytes_read = inbuf.length;
|
|
|
|
bytes_written = inbuf.length;
|
|
|
|
if ((flags & ConverterFlags.INPUT_AT_END) != 0) {
|
|
|
|
if (attached_taglen > 0) {
|
|
|
|
Memory.copy((uint8*)outbuf + inbuf.length, get_tag(attached_taglen), attached_taglen);
|
|
|
|
bytes_written = inbuf.length + attached_taglen;
|
|
|
|
}
|
|
|
|
return ConverterResult.FINISHED;
|
|
|
|
}
|
|
|
|
if ((flags & ConverterFlags.FLUSH) != 0) {
|
|
|
|
return ConverterResult.FLUSHED;
|
|
|
|
}
|
|
|
|
return ConverterResult.CONVERTED;
|
|
|
|
} catch (Crypto.Error e) {
|
|
|
|
throw new IOError.FAILED(@"$(e.domain) error while decrypting: $(e.message)");
|
2019-09-10 18:55:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public class SymmetricCipherDecrypter : SymmetricCipherConverter {
|
|
|
|
public SymmetricCipherDecrypter(owned SymmetricCipher cipher, size_t attached_taglen = 0) {
|
|
|
|
this.cipher = (owned) cipher;
|
|
|
|
this.attached_taglen = attached_taglen;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override ConverterResult convert(uint8[] inbuf, uint8[] outbuf, ConverterFlags flags, out size_t bytes_read, out size_t bytes_written) throws IOError {
|
|
|
|
if (inbuf.length > outbuf.length + attached_taglen) {
|
|
|
|
throw new IOError.NO_SPACE("CipherConverter needs at least the size of input as output space");
|
|
|
|
}
|
|
|
|
if ((flags & ConverterFlags.INPUT_AT_END) != 0 && inbuf.length < attached_taglen) {
|
|
|
|
throw new IOError.PARTIAL_INPUT("CipherConverter needs additional input to read tag");
|
|
|
|
} else if ((flags & ConverterFlags.INPUT_AT_END) == 0 && inbuf.length < attached_taglen + 1) {
|
|
|
|
throw new IOError.PARTIAL_INPUT("CipherConverter needs additional input to make sure to not accidentally read tag");
|
|
|
|
}
|
2019-09-16 21:47:38 +00:00
|
|
|
try {
|
|
|
|
inbuf.length -= (int) attached_taglen;
|
|
|
|
if (inbuf.length > 0) {
|
|
|
|
cipher.decrypt(outbuf, inbuf);
|
2019-09-10 18:55:24 +00:00
|
|
|
}
|
2019-09-16 21:47:38 +00:00
|
|
|
bytes_read = inbuf.length;
|
|
|
|
bytes_written = inbuf.length;
|
|
|
|
inbuf.length += (int) attached_taglen;
|
|
|
|
if ((flags & ConverterFlags.INPUT_AT_END) != 0) {
|
|
|
|
if (attached_taglen > 0) {
|
|
|
|
check_tag(inbuf[(inbuf.length - attached_taglen):inbuf.length]);
|
|
|
|
bytes_read = inbuf.length;
|
|
|
|
}
|
|
|
|
return ConverterResult.FINISHED;
|
|
|
|
}
|
|
|
|
if ((flags & ConverterFlags.FLUSH) != 0) {
|
|
|
|
return ConverterResult.FLUSHED;
|
|
|
|
}
|
|
|
|
return ConverterResult.CONVERTED;
|
|
|
|
} catch (Crypto.Error e) {
|
|
|
|
throw new IOError.FAILED(@"$(e.domain) error while decrypting: $(e.message)");
|
2019-09-10 18:55:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-18 17:53:14 +00:00
|
|
|
}
|