namespace ode {
-EcryptfsEngine::EcryptfsEngine(const std::string& src, const std::string& dest) :
- source(src), destination(dest)
+EcryptfsEngine::EcryptfsEngine(const std::string &src, const std::string &dest) :
+ mSource(src), mDestination(dest)
{
}
{
}
-void EcryptfsEngine::mount(const EcryptfsEngine::data& key)
+key_serial_t EcryptfsEngine::add_key(const char *type,
+ const char *description,
+ const void *payload,
+ size_t plen,
+ key_serial_t ringid)
{
- //TODO
+ return ::syscall(__NR_add_key, type, description, payload, plen, ringid);
}
-void EcryptfsEngine::umount()
+long EcryptfsEngine::keyctl_search(key_serial_t ringid,
+ const char *type,
+ const char *description,
+ key_serial_t destringid)
{
- //TODO
+ return ::syscall(__NR_keyctl, KEYCTL_SEARCH, ringid, type, description, destringid);
}
-void EcryptfsEngine::encrypt(const EcryptfsEngine::data& key)
+void EcryptfsEngine::hexConvert(char *dest, unsigned char *src, int srcLen)
{
- //TODO
+ for (int i = 0; i < srcLen; i++)
+ ::sprintf(&dest[i * 2], "%.2x", (unsigned char)src[i]);
+ dest[srcLen * 2] = '\0';
}
+int EcryptfsEngine::add_user_auth_token_to_keyring(ecryptfs_payload *payload)
+{
+ int result = ERR_NO;
+
+ if (keyctl_search(KEY_SPEC_USER_KEYRING, AUTH_TOKEN_TYPE,
+ (const char *)payload->token.password.signature, 0) <= 0) {
+ if (add_key(AUTH_TOKEN_TYPE, (const char *)payload->token.password.signature,
+ (void *)payload, sizeof(ecryptfs_payload), KEY_SPEC_USER_KEYRING) <= 0) {
+ result = ERR_FAILED_AUTH;
+ } else {
+ std::cout << "Token added = " << payload->token.password.signature << std::endl;
+ }
+ }
+
+ return result;
+}
+
+int EcryptfsEngine::smack_check(void)
+{
+ struct statfs sfs;
+ int ret;
+ int checksmack = 0;
+
+ do {
+ ret = ::statfs(SMACKFS_MNT, &sfs);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret == 0 && sfs.f_type == SMACKFS_MAGIC)
+ checksmack = 1;
+ return checksmack;
+}
+
+void EcryptfsEngine::build_ecryptfs_options(char *ecryptfs_opts, char *sig, int excludeMediaTypes)
+{
+ ::sprintf(ecryptfs_opts, ECRYPTFS_PLAINTEXT_PASSTHOUGH","
+ ECRYPTFS_SIGNATURE"%s,"
+ ECRYPTFS_CIPHERA"%s,"
+ ECRYPTFS_KEY_BYTES"%d", sig, ECRYPTFS_FEK_CIPHER, MAX_KEY_BYTES);
+
+ if (excludeMediaTypes == EXCL_MEDIA_ON) {
+ std::cout << "building options with media files filtering." << std::endl;
+ ::strcat(ecryptfs_opts, ",");
+ ::strcat(ecryptfs_opts, ECRYPTFS_ENABLE_FILTERING);
+ ::strcat(ecryptfs_opts, ECRYPTFS_MEDIA_EXCLUSION_LIST);
+ } else if (excludeMediaTypes == EXCL_ALL_NEW_ON) {
+ std::cout << "building options with all new files filtering." << std::endl;
+ ::strcat(ecryptfs_opts, ",");
+ ::strcat(ecryptfs_opts, ECRYPTFS_ENABLE_FILTERING);
+ ::strcat(ecryptfs_opts, ECRYPTFS_GLOBAL_EXCLUSION_LIST);
+ } else {
+ std::cout << "building options without file encryption filtering." << std::endl;
+ }
+ if (smack_check()) {
+ std::cout << "smack fs was enabled, add smack labeling" << std::endl;
+ ::strcat(ecryptfs_opts, ",");
+ ::strcat(ecryptfs_opts, SMACKFS_MOUNT_OPT);
+ }
+}
+
+int EcryptfsEngine::mount(const data &key)
+{
+ int result = ERR_NO;
+ unsigned char master_key[MAX_KEY_BYTES] = {0};
+ char ecryptfs_opts[ECRYPTFS_MAX_OPTIONS] = {0};
+ std::cout << "Source: " << mSource << std::endl;
+ std::cout << "Destination: " << mDestination << std::endl;
+ std::cout << "EcryptfsMount: ";
+ if (key.size() == 0)
+ return -1;
+
+ for (unsigned int iter = 0; iter < key.size(); iter++) {
+ master_key[iter] = key[iter];
+ }
+
+ if (isEcryptfsMountpointMounted(mDestination) == 0) {
+ std::cout << "Already Mounted" << std::endl;
+ return 0;
+ }
+
+ //MOUNT_ECRYPTFS_DRIVE
+ memset(&(sde_payload), 0, sizeof(ecryptfs_payload));
+
+ sde_payload.version = ECRYPTFS_VERSION;
+ sde_payload.token_type = ECRYPTFS_PWD_PAYLOAD_TYPE;
+ sde_payload.token.password.session_key_encryption_key_bytes = MAX_KEY_BYTES;
+ sde_payload.token.password.flags = ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET;
+ memcpy(sde_payload.token.password.session_key_encryption_key, master_key, MAX_KEY_BYTES);
+
+ hexConvert((char *)sde_payload.token.password.signature, master_key, SIG_SIZE);
+
+ result = add_user_auth_token_to_keyring(&sde_payload);
+ if (result == ERR_NO) {
+ build_ecryptfs_options(ecryptfs_opts, (char *)sde_payload.token.password.signature, mExcludeMedia);
+ std::cout << "encrypted fs option : " << ecryptfs_opts << ", source : " << mSource << ", dest : " << mDestination << std::endl;
+ if (::mount(mSource.c_str(), mDestination.c_str(), ECRYPTFS_MOUNT_DEVICE, MS_NODEV, ecryptfs_opts) != 0) {
+ std::cout << "Unable to mount drive: " << strerror(errno) << std::endl;
+ result = ERR_MOUNT;
+ } else {
+ std::cout << "Mount is completed." << std::endl;
+ }
+ } else {
+ std::cout << "Unable to add token to keyring" << std::endl;
+ }
+
+ return result;
+}
+
+int EcryptfsEngine::umount()
+{
+ int result = ERR_NO;
+
+ std::cout << "EcryptfsUmount" << std::endl;
+ if (isEcryptfsMountpointMounted(mDestination) == 0) {
+ if (::umount(mDestination.c_str()) != 0) {
+ if (::umount2(mDestination.c_str(), MNT_EXPIRE) != 0) {
+ std::cout << "Unmount failed for drive " << mDestination.c_str() << "err(" << errno << strerror(errno) << ")" << std::endl;
+ if (errno == EAGAIN) {
+ std::cout << "Trying Unmount again" << std::endl;
+ if (::umount2(mDestination.c_str(), MNT_EXPIRE) != 0) {
+ result = ERR_UNMOUNT;
+ std::cout << "Unmount failed for drive" << mDestination.c_str() << "err(" << errno << strerror(errno) << ")" << std::endl;
+ }
+ } else {
+ std::cout << "Drive " << mDestination.c_str() << "unmounted failed " << std::endl;
+ result = ERR_UNMOUNT;
+ }
+ }
+ }
+
+ if (result == ERR_NO)
+ std::cout << "Drive " << mDestination.c_str() << " unmounted successfully" << std::endl;
+ else
+ std::cout << "Drive " << mDestination.c_str() << " unmounted failed" << std::endl;
+ }
+ return result;
+}
+
+int EcryptfsEngine::encrypt(const data &key)
+{
+ int result = ERR_NO;
+
+ std::cout << "EcryptfsEncrypt" << std::endl;
+ if (!isMountpointMounted(mSource)) {
+ std::cout << "SD Card not inserted!" << std::endl;
+ return -1;
+ }
+
+ result = DoCrypt(key, mDestination.c_str(), 1, EXCL_MEDIA_ON);
+
+ return result;
+}
+
+int EcryptfsEngine::decrypt(const data &key)
+{
+ int result = ERR_NO;
+
+ std::cout << "EcryptfsDecrypt" << std::endl;
+ if (!isMountpointMounted(mSource)) {
+ std::cout << "SD Card not inserted!" << std::endl;
+ return -1;
+ }
+
+ result = DoCrypt(key, mDestination.c_str(), 0, EXCL_ALL_NEW_ON);
+ return result;
+}
+
+int EcryptfsEngine::DoCrypt(const data &key, const char *path, int reqEnc, int excludeMedia)
+{
+ const char *cryptTempFile = CRYPT_META_FILE;
+ std::cout << "DoCrypt: reqEnc: " << reqEnc << ", excludeMedia: " << excludeMedia << std::endl;
+
+ mPath = path;
+ mReqEnc = reqEnc;
+ mExcludeMedia = excludeMedia;
+ mMetaDataFile = new char[::strlen(mPath) +::strlen(cryptTempFile) + 2];
+ if (mMetaDataFile) {
+ ::sprintf(mMetaDataFile, "%s%s%s", mPath, "/", cryptTempFile);
+ }
+
+ if (reqEnc)
+ DoEncrypt(key);
+ else
+ DoDecrypt(key);
+
+ return 0;
+}
+
+int EcryptfsEngine::DoEncrypt(const data &key)
+{
+ std::cout << "DoEncrypt()" << std::endl;
+
+ if (mount(key) != ERR_NO) {
+ std::cout << "EcryptfsEngine: Error mounting " << mPath << std::endl;
+ goto error;
+ }
+
+ if (createEncryptMetaData(mMetaDataFile) != 0) {
+ goto error;
+ }
+
+ if (preScanForEncrypt(mPath) != 0) {
+ goto error;
+ }
+
+ if (mTotalFileCt) {
+ mTotalCopied = 0;
+ std::cout << "calling the recursive function EncryptFile (" << mPath << ")" << std::endl;
+ if (cryptInplace(mPath, "", false) != 0) {
+ std::cout << "Ecryptfs: Full Encryption couldn't complete" << std::endl;
+ goto error;
+ }
+ }
+
+ return 0;
+error:
+ deleteEncryptMetaData(mMetaDataFile);
+ umount();
+ return -1;
+}
+
+int EcryptfsEngine::DoDecrypt(const data &key)
+{
+ std::cout << "DoDecrypt()" << std::endl;
+
+ if (checkEncryptMetaData(ORIG_META_FILE_PATH) != 0) {
+ goto success;
+ }
+
+ if (mount(key) != ERR_NO) {
+ std::cout << "EcryptfsEngine: Error mounting " << mPath << std::endl;
+ goto error;
+ }
+
+ if (preScanForDecrypt(mPath) != 0) {
+ goto error;
+ }
+
+ if (mTotalFileCt) {
+ mTotalCopied = 0;
+ std::cout << "calling the recursive function EncryptFile (" << mPath << ")" << std::endl;
+ if (cryptInplace(mPath, "", true) != 0) {
+ std::cout << "Ecryptfs: Full Decryption couldn't complete" << std::endl;
+ goto error;
+ }
+ }
+
+ deleteEncryptMetaData(mMetaDataFile);
+success:
+ std::cout << "Decryption Completed !!!" << std::endl;
+ umount();
+ return 0;
+error:
+ umount();
+ return -1;
+}
+
+long long EcryptfsEngine::CopyImpl(int sfd, int dfd, long long fullsz, bool enctype)
+{
+ long long ret = -1;
+ long long total = 0;
+
+ char buffer [ECRYPTFS_BUFFER_SIZE];
+
+ std::cout << "CopyImpl" << std::endl;
+ while (1) {
+ ssize_t rdsz = 0;
+
+ rdsz = FullRead(sfd, buffer, ECRYPTFS_BUFFER_SIZE);
+ if (!rdsz) {
+ ret = 0;
+ break;
+ }
+
+ if (rdsz < 0) {
+ std::cout << "Error reading src file" << std::endl;
+ break;
+ }
+
+ if (dfd >= 0) {
+ ssize_t wrsz = FullWrite(dfd, buffer, rdsz);
+ if (wrsz < rdsz) {
+ std::cout << "Write Error" << std::endl;
+ break;
+ }
+ }
+ total += rdsz;
+ mTotalCopied += rdsz;
+ }
+
+ return ret ? -1 : total;
+}
+
+ssize_t EcryptfsEngine::FullRead(int fd, void *buf, size_t count)
+{
+ ssize_t n;
+
+ do {
+ n = ::read(fd, buf, count);
+ } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+ssize_t EcryptfsEngine::FullWrite(int fd, const void *buf, size_t len)
+{
+ ssize_t total = 0;
+
+ while (len) {
+ ssize_t n;
+
+ do {
+ n = ::write(fd, buf, len);
+ } while (n < 0 && errno == EINTR);
+
+ if (n < 0) {
+ if (total)
+ return total;
+ return n;
+ }
+
+ total += n;
+ buf = ((const char *)buf) + n;
+ len -= n;
+ }
+
+ return total;
+}
+
+int EcryptfsEngine::CopyFile(const char *src, const char *dest, struct stat *src_stat, bool enctype)
+{
+ int sfd, dfd;
+ struct utimbuf times;
+ long long retval = 0;
+
+ std::cout << "Copy start " << src << " => " << dest << std::endl;
+
+ sfd = ::open(src, O_RDONLY, 0666);
+
+ if (sfd < 0) {
+ std::cout << "Cann't open " << src << std::endl;
+ return -1;
+ }
+
+ dfd = ::open(dest, O_WRONLY | O_CREAT | O_TRUNC, src_stat->st_mode);
+ if (dfd < 0) {
+ std::cout << "Error opening the destination file " << dest << std::endl;
+ ::close(sfd);
+ return -1;
+ }
+
+ retval = CopyImpl(sfd, dfd, src_stat->st_size, enctype);
+
+ if (retval < 0) {
+ std::cout << "Encryption Error CopyData returned <" << retval << "> : <" << src << "> errno " << errno << " " << strerror(errno) << std::endl;
+ ::close(sfd);
+ ::close(dfd);
+ return retval;
+ }
+
+ times.actime = src_stat->st_atime;
+ times.modtime = src_stat->st_mtime;
+
+ if (::utime(dest, ×) < 0)
+ std::cout << "can't preserve times of '" << src << "'" << std::endl;
+
+ std::cout << "Copy Completed" << std::endl;
+
+ if (::fsync(dfd) != 0)
+ std::cout << "can't fsync of '" << src << "'" << std::endl;
+ if (::posix_fadvise(dfd, 0, src_stat->st_size, POSIX_FADV_DONTNEED) < 0)
+ std::cout << "can't fadvise of '" << dest << "'" << std::endl;
+
+ ::close(sfd);
+ ::close(dfd);
+
+ return 0;
+}
+
+void EcryptfsEngine::syncdatafile(const char *src)
+{
+ int sfd;
+ sfd = ::open(src, O_WRONLY);
+ if (sfd < 0) {
+ std::cout << "Cann't open " << src << std::endl;
+ return;
+ }
+ if (::fsync(sfd) != 0)
+ std::cout << "can't fsync of '" << src << "'" << std::endl;
+ /* just open and close for flushing file to ecryptfs */
+ ::close(sfd);
+}
+int EcryptfsEngine::cryptInplace(const char *src, const char *tmpdest, bool dec_fl)
+{
+ struct stat src_stat;
+ int retval = 0;
+ int enc_fl = 0;
+
+ if (::lstat(src, & src_stat) < 0)
+ std::cout << "source : < " << src << "> is a dangling link" << std::endl;
+
+ if (S_ISDIR(src_stat.st_mode)) {
+ /* dir call recursively */
+ DIR *dp;
+ struct dirent *d;
+
+ dp = ::opendir(src);
+ if (NULL == dp) {
+ retval = -1;
+ return retval;
+ }
+
+ while ((d = ::readdir(dp)) != NULL) {
+ char *nsrc = NULL;
+ char *ntmpdest = NULL;
+
+ nsrc = catSubpathFile(src, d->d_name, &ntmpdest);
+ if (nsrc == NULL) {
+ if (ntmpdest != NULL) delete [] ntmpdest;
+ continue;
+ }
+
+ if (cryptInplace(nsrc, ntmpdest, dec_fl) < 0) {
+ std::cout << "Encryptfile returned error for nsrc <" << nsrc << ">" << std::endl;
+ retval = -1;
+ delete [] ntmpdest;
+ delete [] nsrc;
+ break;
+ }
+ delete [] ntmpdest;
+ delete [] nsrc;
+ }
+ ::closedir(dp);
+ } else if (S_ISREG(src_stat.st_mode)) {
+ enc_fl = fn_was_encrypted(src);
+
+ if (enc_fl == WAS_ECRYPTED_ERROR)
+ return enc_fl;
+ if ((!dec_fl && enc_fl == WAS_NOT_ENCRYPTED) ||
+ (dec_fl && enc_fl == WAS_ENCRYPTED)) {
+ std::cout << "ENC/DEC " << src << std::endl;
-void EcryptfsEngine::decrypt(const EcryptfsEngine::data& key)
+ retval = CopyFile(src, tmpdest, &src_stat, dec_fl);
+ if (retval) {
+ std::cout << "CopyFileImpl returned error <" << retval << "> errno " << errno << strerror(errno) << std::endl;
+ return retval;
+ }
+ ::unlink(src);
+ retval = ::rename(tmpdest, src);
+ syncdatafile(src);
+ if (retval) {
+ std::cout << "rename returned error <" << retval << "> errno " << errno << strerror(errno) << std::endl;
+ return retval;
+ }
+ } else
+ std::cout << "File already encrpyted/Decrypted : <" << src << ">" << std::endl;
+ }
+
+ return retval;
+}
+
+int EcryptfsEngine::preScanForEncrypt(const char *src)
+{
+ sizeinfo_type szinfo;
+ struct statfs statbuf;
+ int result = ERR_NO;
+
+ std::cout << "preScanForEncrypt" << std::endl;
+ do {
+ ::memset(&szinfo, 0, sizeof(sizeinfo_type));
+ if (!::statfs(src, &statbuf)) {
+ szinfo.availsz = (long long)statbuf.f_bfree * statbuf.f_bsize;
+ szinfo.blocksz = (int)statbuf.f_bsize;
+ std::cout << "Free size available from statfs : <" << szinfo.availsz << ">" << std::endl;
+ } else {
+ std::cout << "can't access " << src << std::endl;
+ return PRESCAN_ERR;
+ }
+
+ mPreScanEncryptErr = 0;
+ result = getEncryptedSize(src, &szinfo);
+
+ std::cout << "Prescan Free <" << szinfo.availsz << ">, source size <" << szinfo.cursz << ">, Source Encrypted size <" << szinfo.encsz << "> largeFileSz <"
+ << szinfo.largesz << "> filecount <" << szinfo.filecount << "> for <" << src << ">" << std::endl;
+ std::cout << "retval <" << result << "> PrescanencryptErr <" << mPreScanEncryptErr << ">" << std::endl;
+
+ mTotalFileCt = szinfo.filecount;
+ mTotalStSz = szinfo.totalstsz;
+
+ if (mPreScanEncryptErr == PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR) {
+ result = PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR;
+ } else if ((mPreScanEncryptErr == PRESCAN_ERR) || (result == PRESCAN_ERR)) {
+ int total = (szinfo.encsz + szinfo.largesz - szinfo.cursz + 12 * 1024) / 1024;
+ int needed = total - szinfo.availsz / 1024;
+
+ if (isEcryptfsMountpointMounted(mPath)) {
+ umount();
+ std::cout << "Unmounting mpath <" << mPath << ">" << std::endl;
+ }
+
+ std::cout << "Prescan failed with Too full error, need more space, " << needed << " extra, total " << total << std::endl;
+ result = PRESCAN_ERR;
+ }
+
+ if (result == PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR) {
+ std::cout << "EcryptfsEngine: Need to run Prescan Again" << std::endl;
+ continue;
+ }
+
+ if (result == 0) {
+ std::cout << "EcryptfsEngine: Prescan completed successfully" << std::endl;
+ return result;
+ }
+
+ std::cout << "EcryptfsEngine: Cannot encrypt, Disk Space is not enough" << std::endl;
+ return PRESCAN_ERR;
+ } while (1);
+}
+
+int EcryptfsEngine::preScanForDecrypt(const char *src)
+{
+ sizeinfo_type szinfo;
+ struct statfs statbuf;
+ int result = ERR_NO;
+
+ std::cout << "preScanForDecrypt" << std::endl;
+ do {
+ ::memset(&szinfo, 0, sizeof(EcryptfsEngine::sizeinfo_type));
+ if (!::statfs(src, &statbuf)) {
+ szinfo.availsz = (long long)statbuf.f_bfree * statbuf.f_bsize;
+ szinfo.blocksz = (int)statbuf.f_bsize;
+ std::cout << "Free size available from statfs : <" << szinfo.availsz << ">" << std::endl;
+ } else {
+ std::cout << "can't access " << src << std::endl;
+ return PRESCAN_ERR;
+ }
+
+ mPreScanEncryptErr = 0;
+ result = getDecryptedSize(src, &szinfo);
+
+ std::cout << "Prescan Decrypt Free <" << szinfo.availsz << ">, source size <" << szinfo.cursz << ">, Source Decrypted size <" << szinfo.decsz << "> largeFileSz <"
+ << szinfo.largesz << "> filecount <" << szinfo.filecount << "> for <" << src << ">" << std::endl;
+ std::cout << "retval <" << result << "> PrescanencryptErr <" << mPreScanEncryptErr << ">" << std::endl;
+
+ mTotalFileCt = szinfo.filecount;
+ mTotalStSz = szinfo.totalstsz;
+
+ if (mPreScanEncryptErr == PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR) {
+ result = PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR;
+ } else if ((mPreScanEncryptErr == PRESCAN_ERR) || (result == PRESCAN_ERR)) {
+ int total = (szinfo.encsz + szinfo.largesz - szinfo.cursz + 12 * 1024) / 1024;
+ int needed = total - szinfo.availsz / 1024;
+
+ if (isEcryptfsMountpointMounted(mPath)) {
+ umount();
+ std::cout << "Unmounting mpath <" << mPath << ">" << std::endl;
+ }
+
+ std::cout << "Prescan failed with Too full error, need more space, " << needed << " extra, total " << total << std::endl;
+ result = PRESCAN_ERR;
+ }
+
+ if (result == PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR) {
+ std::cout << "EcryptfsEngine: Need to run Prescan Again" << std::endl;
+ continue;
+ }
+
+ if (result == 0) {
+ std::cout << "EcryptfsEngine: Prescan completed successfully" << std::endl;
+ return 0;
+ }
+
+ std::cout << "EcryptfsEngine: Cannot encrypt, Disk Space is not enough" << std::endl;
+ return PRESCAN_ERR;
+ } while (1);
+}
+
+int EcryptfsEngine::getEncryptedSize(const char *src, EcryptfsEngine::sizeinfo_type *szinfo)
+{
+ struct stat src_stat;
+ int result = ERR_NO;
+ std::cout << "getEncryptedSize: " << src << std::endl;
+ if (::lstat(src, &src_stat) < 0)
+ std::cout << "getEncryptedSize: source : <" << src << "> is a dangling link" << std::endl;
+ if (S_ISDIR(src_stat.st_mode)) {
+ /* dir call recursively */
+ DIR *dp;
+ struct dirent *d;
+
+ /* TODO check for recursion
+ * no need to Create dir
+ * */
+ dp = ::opendir(src);
+ if (NULL == dp) {
+ result = -1;
+ std::cout << "getEncryptedSize: opendir return null <" << src << ">" << std::endl;
+ return result;
+ }
+
+ while ((d = ::readdir(dp)) != NULL) {
+ char *nsrc = NULL;
+ char *ntmpdest = NULL;
+
+ nsrc = catSubpathFile(src, d->d_name, &ntmpdest);
+
+ if (nsrc == NULL) {
+ if (ntmpdest) delete [] ntmpdest;
+ continue;
+ }
+
+ if ((result = getEncryptedSize(nsrc, szinfo)) < 0) {
+ std::cout << "getEncryptedSize() reutnred error for nsrc <" << nsrc << "> result < " << result << ">" << std::endl;
+ if (result == PRESCAN_ERR)
+ mPreScanEncryptErr = result;
+ }
+ delete [] ntmpdest;
+ delete [] nsrc;
+ }
+ ::closedir(dp);
+ } else if (S_ISREG(src_stat.st_mode)) {
+ long long padded_sz = src_stat.st_size;
+ long long new_enc_sz = 0;
+ int enc_fl = fn_was_encrypted(src);
+
+ std::cout << "fn_was_encrypted returned: " << enc_fl << std::endl;
+
+ if (padded_sz % 4096)
+ padded_sz = (1 + padded_sz / 4096) * 4096;
+
+ if (enc_fl != WAS_NOT_ENCRYPTED) {
+ std::cout << "Skipping " << src << std::endl;
+ new_enc_sz = padded_sz;
+ } else {
+ std::cout << "PRE ENC " << src << std::endl;
+ std::cout << "fn_was_encrypted returned: " << enc_fl << std::endl;
+ new_enc_sz = padded_sz + 2 * 4096;
+
+ if (szinfo->largesz < src_stat.st_size)
+ szinfo->largesz = src_stat.st_size;
+
+ szinfo->filecount += 1;
+ szinfo->totalstsz += src_stat.st_size;
+ }
+
+ // Pad it to block size
+ if (new_enc_sz % szinfo->blocksz)
+ new_enc_sz = (1 + new_enc_sz / szinfo->blocksz) * szinfo->blocksz;
+
+ szinfo->encsz += new_enc_sz;
+
+ if ((enc_fl == WAS_NOT_ENCRYPTED) && ((szinfo->encsz - szinfo->cursz) > szinfo->availsz)) {
+ if (mPreScanEncryptErr == PRESCAN_TEMP_FILE_EXIST_ERR) {
+ result = PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR;
+ } else
+ result = PRESCAN_ERR;
+ }
+
+ {
+ long long padded_cursz = src_stat.st_size;
+
+ if (padded_cursz % szinfo->blocksz)
+ padded_cursz = (1 + padded_cursz / szinfo->blocksz) * szinfo->blocksz;
+
+ szinfo->cursz += padded_cursz;
+ }
+ }
+
+ return result;
+}
+
+int EcryptfsEngine::getDecryptedSize(const char *src, EcryptfsEngine::sizeinfo_type *szinfo)
+{
+ struct stat src_stat;
+ int result = ERR_NO;
+ std::cout << "getDecryptedSize: " << src << std::endl;
+ if (::lstat(src, & src_stat) < 0)
+ std::cout << "getDecryptedSize: source : <" << src << "> is a dangling link" << std::endl;
+
+ if (S_ISDIR(src_stat.st_mode)) {
+ /* dir call recursively */
+ DIR *dp;
+ struct dirent *d;
+
+ /* TODO check for recursion
+ * no need to Create dir
+ * */
+ dp = ::opendir(src);
+ if (NULL == dp) {
+ result = -1;
+ std::cout << "getDecryptedSize: opendir return null <" << src << ">" << std::endl;
+ return result;
+ }
+
+ while ((d = ::readdir(dp)) != NULL) {
+ char *nsrc = NULL;
+ char *ntmpdest = NULL;
+
+ nsrc = catSubpathFile(src, d->d_name, &ntmpdest);
+
+ if (nsrc == NULL) {
+ if (ntmpdest != NULL) delete [] ntmpdest;
+ continue;
+ }
+
+ if ((result = getDecryptedSize(nsrc, szinfo)) < 0) {
+ std::cout << "getDecryptedSize() reutnred error for nsrc <" << nsrc << "> result < " << result << ">" << std::endl;
+ if (result == PRESCAN_ERR) {
+ mPreScanDecryptErr = result;
+ }
+ }
+ delete [] ntmpdest;
+ delete [] nsrc;
+ }
+ ::closedir(dp);
+ } else if (S_ISREG(src_stat.st_mode)) {
+ long long decsize = 0;
+ long long paddedsize = 0;
+ long long paddedstsz = 0;
+ int enc_fl = fn_was_encrypted(src);
+
+ std::cout << "fn_was_encrypted returned: " << enc_fl << std::endl;
+
+ if (src_stat.st_size > 2 * 4096)
+ decsize = src_stat.st_size - 2 * 4096;
+
+ paddedsize = decsize;
+ if (decsize % szinfo->blocksz)
+ paddedsize = (1 + decsize / szinfo->blocksz) * szinfo->blocksz;
+
+ paddedstsz = src_stat.st_size;
+ if (paddedstsz % szinfo->blocksz)
+ paddedstsz = (1 + paddedstsz / szinfo->blocksz) * szinfo->blocksz;
+
+ if (enc_fl == WAS_ENCRYPTED) {
+ std::cout << "PRE ENC " << src << std::endl;
+ szinfo->filecount += 1;
+ szinfo->totalstsz += src_stat.st_size;
+
+ if (szinfo->largesz < src_stat.st_size)
+ szinfo->largesz = src_stat.st_size;
+
+ if ((decsize > szinfo->availsz) ||
+ (!decsize && (paddedstsz > szinfo->availsz))) {
+ int tmpneeded;
+ std::cout << "Runtime Error source: " << src << ", decsz <" << szinfo->decsz << "> cursz <" << szinfo->cursz << ">, largesz <" <<
+ szinfo->largesz << "> st_size <" << src_stat.st_size << "> availsz <" << szinfo->availsz << ">" << std::endl;
+ if (mPreScanDecryptErr == PRESCAN_TEMP_FILE_EXIST_ERR)
+ result = PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR;
+ else
+ result = PRESCAN_ERR;
+
+ if (decsize)
+ tmpneeded = decsize - szinfo->availsz;
+ else
+ tmpneeded = paddedstsz - szinfo->availsz;
+
+ if (szinfo->neededsz < tmpneeded) {
+ szinfo->neededsz = tmpneeded;
+ if (decsize)
+ szinfo->totalneedsz = decsize;
+ else
+ szinfo->totalneedsz = paddedstsz;
+ }
+ } else {
+ if (decsize) {
+ long long delta = paddedsize - decsize - 2 * 4096;
+
+ szinfo->decsz += paddedsize;
+ if (delta > 0)
+ szinfo->availsz += delta;
+ } else
+ szinfo->decsz += paddedstsz;
+
+ szinfo->cursz += paddedstsz;
+ }
+ } else {
+ std::cout << "in decrypting case fn_was_encrypted returned: " << enc_fl << std::endl;
+ std::cout << "Skipping " << src << std::endl;
+ szinfo->decsz += paddedstsz;
+ szinfo->cursz += paddedstsz;
+ }
+ }
+
+ return result;
+}
+
+char *EcryptfsEngine::catSubpathFile(const char *src, const char *filename, char **prefixtmp)
+{
+ if (src == NULL || filename == NULL || prefixtmp == NULL)
+ return NULL;
+
+ char *catstr = new char[::strlen(src) + ::strlen(filename) + 2];
+ int len = ::strlen(src);
+ const char *prefix = ".tmp_eCfs";
+
+ if (filename && check_dots(filename)) {
+ delete [] catstr;
+ return NULL;
+ }
+
+ *prefixtmp = new char[::strlen(src) + ::strlen(filename) + ::strlen(prefix) + 2];
+
+ while (*filename == '/')
+ filename++;
+
+ if (src [len - 1] == '/') {
+ ::sprintf(catstr, "%s%s", src, filename);
+ ::sprintf(*prefixtmp, "%s%s%s", src, prefix, filename);
+ } else {
+ ::sprintf(catstr, "%s%s%s", src, "/", filename);
+ ::sprintf(*prefixtmp, "%s%s%s%s", src, "/", prefix, filename);
+ }
+
+ if (!::strncmp(filename, prefix, ::strlen(prefix))) {
+ std::cout << "Deleting Existing Temp file " << filename << std::endl;
+ if (!mPreScanEncryptErr)
+ mPreScanEncryptErr = PRESCAN_TEMP_FILE_EXIST_ERR;
+ else
+ mPreScanEncryptErr = PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR;
+ if (!mPreScanDecryptErr)
+ mPreScanDecryptErr = PRESCAN_TEMP_FILE_EXIST_ERR;
+ else
+ mPreScanDecryptErr = PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR;
+ ::unlink(catstr);
+ delete [] * prefixtmp;
+ delete [] catstr;
+ *prefixtmp = NULL;
+ return NULL;
+ }
+
+ return catstr;
+}
+
+int EcryptfsEngine::fn_was_encrypted(const char *filePath)
+{
+ int fd = 0;
+ int ret = WAS_NOT_ENCRYPTED;
+ __u32 attrs = 0;
+
+ if (filePath == NULL) {
+ std::cout << "Ecryptfs: fn_was_encrypted: source file path is null" << std::endl;
+ return WAS_ECRYPTED_ERROR;
+ }
+
+ fd = ::open(filePath, O_RDWR);
+ if (fd < 0) {
+ std::cout << "Ecryptfs: fn_was_encrypted: cannot open file " << strerror(errno) << std::endl;
+ return WAS_ECRYPTED_ERROR;
+ }
+
+ if (::ioctl(fd, ECRYPTFS_IOCTL_GET_ATTRIBUTES, &attrs)) {
+ std::cout << "Ecryptfs: fn_was_encrypted: ioctl fail " << strerror(errno) << std::endl;
+ ::close(fd);
+ return WAS_ECRYPTED_ERROR;
+ }
+
+ std::cout << "Ecryptfs: IOCT_GET_ATTRIBUTE = " << attrs << std::endl;
+ if ((attrs & ECRYPTFS_WAS_ENCRYPTED) == ECRYPTFS_WAS_ENCRYPTED)
+ ret = WAS_ENCRYPTED;
+ else if ((attrs & ECRYPTFS_WAS_ENCRYPTED_OTHER_DEVICE) == ECRYPTFS_WAS_ENCRYPTED_OTHER_DEVICE)
+ ret = WAS_ENCRYPTED_OTHER_DEVICE;
+
+ ::close(fd);
+
+ return ret;
+}
+
+int EcryptfsEngine::createEncryptMetaData(const char *filename)
{
- //TODO
+ int fd = -1;
+ std::cout << "createEncryptMetaData" << std::endl;
+
+ fd = ::open(filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ if (fd < 0) {
+ std::cout << "Cann't open " << filename << std::endl;
+ return -1;
+ }
+ if (::fsync(fd) != 0)
+ std::cout << "Cann't fsync of '" << filename << "'" << std::endl;
+ ::close(fd);
+ return 0;
}
+int EcryptfsEngine::checkEncryptMetaData(const char *path)
+{
+ struct stat src_stat;
+ int retval = 0;
+
+ if (path == NULL) {
+ if (mMetaDataFile) {
+ if (::lstat(mMetaDataFile, &src_stat) < 0)
+ if (errno == ENOENT)
+ retval = -1;
+ }
+ } else {
+ std::cout << path << std::endl;
+ if (::stat(path, &src_stat) < 0)
+ if (errno == ENOENT)
+ retval = -1;
+ }
+ return retval;
+}
+
+void EcryptfsEngine::deleteEncryptMetaData(const char *filename)
+{
+ if (checkEncryptMetaData(filename) == 0)
+ ::unlink(filename);
+}
+
+int EcryptfsEngine::isMountpointMounted(const std::string &path)
+{
+ char device[256];
+ char mount_path[256];
+ char rest[256];
+ FILE *fp;
+ char line[1024];
+
+ if (!(fp = ::fopen("/proc/mounts", "r"))) {
+ std::cout << "Error opening /proc/mounts (" << strerror(errno) << ")" << std::endl;
+ return 0;
+ }
+
+ while (::fgets(line, sizeof(line), fp)) {
+ line[::strlen(line) - 1] = '\0';
+ ::sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
+ if (!::strcmp(mount_path, path.c_str())) {
+ ::fclose(fp);
+ return 1;
+ }
+ }
+
+ ::fclose(fp);
+ return 0;
+}
+
+int EcryptfsEngine::isEcryptfsMountpointMounted(const std::string &path)
+{
+ char device[256];
+ char mount_path[256];
+ char dev_path[256];
+ char rest[256];
+ FILE *fp;
+ char line[1024];
+
+ if (!(fp = ::fopen("/proc/mounts", "r"))) {
+ std::cout << "Error opening /proc/mounts (" << strerror(errno) << ")" << std::endl;
+ return -1;
+ }
+
+ while (::fgets(line, sizeof(line), fp)) {
+ line[strlen(line) - 1] = '\0';
+ ::sscanf(line, "%255s %255s %255s %255s\n", dev_path, mount_path, device, rest);
+ if (!::strcmp(mount_path, path.c_str()) && !strcmp(device, "ecryptfs")) {
+ ::fclose(fp);
+ std::cout << "Returning True mount_path<" << mount_path << ">,path <" << path << ">, device <" << device << ">" << std::endl;
+ return 0;
+ }
+ }
+
+ fclose(fp);
+ return -1;
+}
} // namespace ode
#include <vector>
#include <string>
+#include <sys/mount.h>
+#include <sys/syscall.h>
+#include <sys/vfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <utime.h>
+
+#define __u32 unsigned int
+
+#define ECRYPTFS_SIG_SIZE 8
+#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
+#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
+#define ECRYPTFS_MAX_KEY_BYTES 64
+#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
+#define ECRYPTFS_MAX_PKI_NAME_BYTES 16
+#define ECRYPTFS_SALT_SIZE 8
+#define ECRYPTFS_BUFFER_SIZE 4096
+
+#define ECRYPTFS_MAJOR_VERSION 0x00
+#define ECRYPTFS_MINOR_VERSION 0x04
+#define ECRYPTFS_VERSION ((ECRYPTFS_MAJOR_VERSION << 8) | ECRYPTFS_MINOR_VERSION)
+#define ECRYPTFS_PWD_PAYLOAD_TYPE 0
+#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
+
+#define MAX_KEY_BYTES 32
+#define SIG_SIZE 8
+#define ECRYPTFS_MAX_OPTIONS 1024
+
+#define ECRYPTFS_PLAINTEXT_PASSTHOUGH "ecryptfs_passthrough"
+#define ECRYPTFS_SIGNATURE "ecryptfs_sig="
+#define ECRYPTFS_CIPHERA "ecryptfs_cipher="
+#define ECRYPTFS_KEY_BYTES "ecryptfs_key_bytes="
+#define ECRYPTFS_UNLINK_SIGNATURE "ecryptfs_unlink_sig"
+#define ECRYPTFS_FEK_CIPHER "aes"
+#define ECRYPTFS_ENABLE_FILTERING "ecryptfs_enable_filtering="
+#define ECRYPTFS_MEDIA_EXCLUSION_LIST "temp_video/Camera/DCIM:mp3|mpga|m4a|mp4|wav|amr|awb|wma|ogg|oga|aac|mka|flac|3gp|3ga|mid|midi|xmf|rtttl|rtx|ota|smf|spm|imy|mpeg|m4v|3gp|3gpp|3g2|3gpp2|wmv|asf|mkv|webm|ts|avi|jpg|jpeg|gif|png|bmp|wbmp|divx|flv|ac3|mov|tiff|f4v|mpeg3|voice"
+#define ECRYPTFS_GLOBAL_EXCLUSION_LIST "*"
+
+#define SMACKFS_MAGIC 0x43415d53
+#define SMACKFS_MNT "/smack"
+#define SMACKFS_MOUNT_OPT "smackfsroot=*,smackfsdef=*"
+
+#define EXCL_ALL_NEW_ON 2
+#define EXCL_MEDIA_ON 1
+#define EXCL_MEDIA_OFF 0
+
+typedef int32_t key_serial_t;
+
+#define KEY_SPEC_USER_KEYRING -4 /* - key ID for UID-specific keyring */
+#define KEYCTL_SEARCH 10 /* search for a key in a keyring */
+#define AUTH_TOKEN_TYPE "user"
+#define ECRYPTFS_MOUNT_DEVICE "ecryptfs"
+
+#define CRYPT_META_FILE ".MetaEcfsFile"
+#define ORIG_META_FILE_PATH "/opt/media/SDCardA1/.MetaEcfsFile"
+
+#define ERR_NO 0
+#define ERR_FAILED_AUTH 1
+#define ERR_MOUNT 5
+#define ERR_UNMOUNT 6
+
+#define ECRYPTFS_IOCTL_GET_ATTRIBUTES _IOR('l', 0x10, __u32)
+#define ECRYPTFS_WAS_ENCRYPTED 0x0080
+#define ECRYPTFS_WAS_ENCRYPTED_OTHER_DEVICE 0x0100
+
+#define PRESCAN_ERR (-2)
+#define PRESCAN_TEMP_FILE_EXIST_ERR (-3)
+#define PRESCAN_TEMP_FILE_EXIST_AND_SIZE_ERR (-4)
+
+#define WAS_ECRYPTED_ERROR (-2)
+#define WAS_NOT_ENCRYPTED (-1)
+#define WAS_ENCRYPTED 0
+#define WAS_ENCRYPTED_OTHER_DEVICE 1
+
+#define check_dots(p) ((p)[0] == '.' && (!(p)[1] || ((p)[1] =='.'&& !(p)[2])))
namespace ode {
const std::string& getSource()
{
- return source;
+ return mSource;
}
const std::string& getDestination()
{
- return destination;
+ return mDestination;
+ }
+
+ void setSource(const std::string& src)
+ {
+ mSource = src;
+ }
+
+ void setDestination(const std::string& dest)
+ {
+ mDestination = dest;
}
typedef std::vector<unsigned char> data;
- void mount(const data& key);
- void umount();
+ typedef struct {
+ int blocksz;
+ int filecount;
+ long long availsz;
+ long long decsz;
+ long long encsz;
+ long long cursz;
+ long long largesz;
+ long long neededsz;
+ long long totalneedsz;
+ long long totalstsz;
+ } sizeinfo_type;
+
+ struct ecryptfs_session_key {
+ u_int32_t flags;
+ u_int32_t encrypted_key_size;
+ u_int32_t decrypted_key_size;
+ u_int8_t encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+ u_int8_t decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
+ };
+
+ struct ecryptfs_password {
+ u_int32_t password_bytes;
+ int32_t hash_algo;
+ u_int32_t hash_iterations;
+ u_int32_t session_key_encryption_key_bytes;
+ u_int32_t flags;
+ u_int8_t session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+ u_int8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+ u_int8_t salt[ECRYPTFS_SALT_SIZE];
+ };
- void encrypt(const data& key);
- void decrypt(const data& key);
+ struct ecryptfs_private_key {
+ u_int32_t key_size;
+ u_int32_t data_len;
+ u_int8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+ char pki_type[ECRYPTFS_MAX_PKI_NAME_BYTES + 1];
+ u_int8_t data[];
+ };
+
+ struct ecryptfs_auth_tok {
+ u_int16_t version;
+ u_int16_t token_type;
+ u_int32_t flags;
+ struct ecryptfs_session_key session_key;
+ u_int8_t reserved[32];
+ union {
+ struct ecryptfs_password password;
+ struct ecryptfs_private_key private_key;
+ } token;
+ } __attribute__ ((packed));
+
+ typedef struct ecryptfs_auth_tok ecryptfs_payload;
+
+ key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid);
+ long keyctl_search(key_serial_t ringid, const char *type, const char *description, key_serial_t destringid);
+ void hexConvert(char *dest, unsigned char *src, int srcLen);
+ int add_user_auth_token_to_keyring(ecryptfs_payload *payload) ;
+ int smack_check(void);
+ void build_ecryptfs_options(char *ecryptfs_opts, char *sig, int excludeMediaTypes);
+
+ int mount(const data& key);
+ int umount();
+
+ int encrypt(const data& key);
+ int decrypt(const data& key);
+
+ int DoCrypt(const data& key, const char *path, int reqEnc, int excludeMedia);
+ int DoEncrypt(const data& key);
+ int DoDecrypt(const data& key);
+ long long CopyImpl(int sfd, int dfd, long long fullsz, bool enctype);
+ ssize_t FullRead (int fd, void * buf, size_t count);
+ ssize_t FullWrite (int fd, const void * buf, size_t len);
+ int CopyFile (const char * src, const char * dest, struct stat * src_stat, bool enctype);
+ void syncdatafile (const char * src);
+ int cryptInplace(const char * src, const char * tmpdest, bool dec_fl);
+ int preScanForEncrypt(const char *src);
+ int preScanForDecrypt(const char * src);
+ int getEncryptedSize(const char * src, sizeinfo_type * szinfo);
+ int getDecryptedSize(const char * src, sizeinfo_type * szinfo);
+ char * catSubpathFile(const char * src, const char * filename, char ** prefixtmp);
+ int fn_was_encrypted(const char *filePath);
+ int createEncryptMetaData(const char *filename);
+ int checkEncryptMetaData(const char *path);
+ void deleteEncryptMetaData (const char *filename);
+ int isMountpointMounted(const std::string& path);
+ int isEcryptfsMountpointMounted(const std::string& path);
private:
- std::string source, destination;
+ std::string mSource, mDestination;
+ ecryptfs_payload sde_payload;
+ const char *mPath;
+ char *mMetaDataFile;
+ int mReqEnc;
+ int mExcludeMedia;
+ int mPreScanEncryptErr;
+ int mPreScanDecryptErr;
+ int mTotalFileCt;
+ long long mTotalStSz;
+ long long mTotalCopied;
};
} // namespace ode
#endif // __ECRYPTFS_ENGINE_H__
+