diff --git a/db_structure.xml b/db_structure.xml
index f9470dc86b359f3769a83df225b80190c0c50568..a7225a7661f2bf6954fde45296bd15cecdad6423 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -1077,4 +1077,67 @@
 
 	</table>
 
+	<table>
+
+		<name>*dbprefix*privatedata</name>
+
+		<declaration>
+
+		<field>
+			<name>keyid</name>
+			<type>integer</type>
+			<default>0</default>
+			<notnull>true</notnull>
+			<unsigned>true</unsigned>
+			<length>4</length>
+			<autoincrement>1</autoincrement>
+		</field>
+
+		<field>
+			<name>user</name>
+			<type>text</type>
+			<default></default>
+			<notnull>true</notnull>
+			<length>255</length>
+		</field>
+
+		<field>
+			<name>app</name>
+			<type>text</type>
+			<default></default>
+			<notnull>true</notnull>
+			<length>255</length>
+		</field>
+
+		<field>
+			<name>key</name>
+			<type>text</type>
+			<default></default>
+			<notnull>true</notnull>
+			<length>255</length>
+		</field>
+
+		<field>
+			<name>value</name>
+			<type>text</type>
+			<default></default>
+			<notnull>true</notnull>
+			<length>255</length>
+		</field>
+
+		<index>
+			<primary>true</primary>
+			<unique>true</unique>
+			<name>keyid_index</name>
+			<field>
+				<name>keyid</name>
+				<sorting>ascending</sorting>
+			</field>
+		</index>
+
+		</declaration>
+
+	</table>
+
+
 </database>
diff --git a/lib/private/ocs.php b/lib/private/ocs.php
index 93e8931ce2eabe9603610d83624f500c05bcb54a..e067196cf11132667ff58188483de0d7c8211765 100644
--- a/lib/private/ocs.php
+++ b/lib/private/ocs.php
@@ -228,36 +228,4 @@ class OC_OCS {
 			}
 		}
 	}
-
-	/**
-	* get private data
-	* @param string $user
-	* @param string $app
-	* @param string $key
-	* @param bool $like use LIKE instead of = when comparing keys
-	* @return array
-	*/
-	public static function getData($user, $app="", $key="") {
-		if($app) {
-			$apps=array($app);
-		}else{
-			$apps=OC_Preferences::getApps($user);
-		}
-		if($key) {
-			$keys=array($key);
-		}else{
-			foreach($apps as $app) {
-				$keys=OC_Preferences::getKeys($user, $app);
-			}
-		}
-		$result=array();
-		foreach($apps as $app) {
-			foreach($keys as $key) {
-				$value=OC_Preferences::getValue($user, $app, $key);
-				$result[]=array('app'=>$app, 'key'=>$key, 'value'=>$value);
-			}
-		}
-		return $result;
-	}
-
 }
diff --git a/lib/private/ocs/privatedata.php b/lib/private/ocs/privatedata.php
index 4dfd0a6e66e3482edc454319471f644426a41b5b..932413711b8b8674573285d62e6877562d85cc64 100644
--- a/lib/private/ocs/privatedata.php
+++ b/lib/private/ocs/privatedata.php
@@ -22,45 +22,87 @@
 *
 */
 
+
 class OC_OCS_Privatedata {
 
+	/**
+	 * read keys
+	 * test: curl http://login:passwd@oc/core/ocs/v1.php/privatedata/getattribute/testy/123
+	 * test: curl http://login:passwd@oc/core/ocs/v1.php/privatedata/getattribute/testy
+	 * @param array $parameters The OCS parameter
+	 * @return \OC_OCS_Result
+	 */
 	public static function get($parameters) {
-		OC_Util::checkLoggedIn();
 		$user = OC_User::getUser();
 		$app = addslashes(strip_tags($parameters['app']));
-		$key = addslashes(strip_tags($parameters['key']));
-		$result = OC_OCS::getData($user, $app, $key);
+		$key = isset($parameters['key']) ? addslashes(strip_tags($parameters['key'])) : null;
+		
+		if(empty($key)) {
+			$query = \OCP\DB::prepare('SELECT `key`, `app`, `value`  FROM `*PREFIX*privatedata` WHERE `user` = ? AND `app` = ? ');
+			$result = $query->execute(array($user, $app));
+		} else {
+			$query = \OCP\DB::prepare('SELECT `key`, `app`, `value`  FROM `*PREFIX*privatedata` WHERE `user` = ? AND `app` = ? AND `key` = ? ');
+			$result = $query->execute(array($user, $app, $key));
+		}
+		
 		$xml = array();
-		foreach($result as $i=>$log) {
-			$xml[$i]['key']=$log['key'];
-			$xml[$i]['app']=$log['app'];
-			$xml[$i]['value']=$log['value'];
+		while ($row = $result->fetchRow()) {
+			$data=array();
+			$data['key']=$row['key'];
+			$data['app']=$row['app'];
+			$data['value']=$row['value'];
+		 	$xml[] = $data;
 		}
+
 		return new OC_OCS_Result($xml);
-		//TODO: replace 'privatedata' with 'attribute' once a new libattice has been released that works with it
 	}
 
+	/**
+	 * set a key
+	 * test: curl http://login:passwd@oc/core/ocs/v1.php/privatedata/setattribute/testy/123  --data "value=foobar"
+	 * @param array $parameters The OCS parameter
+	 * @return \OC_OCS_Result
+	 */
 	public static function set($parameters) {
-		OC_Util::checkLoggedIn();
 		$user = OC_User::getUser();
 		$app = addslashes(strip_tags($parameters['app']));
 		$key = addslashes(strip_tags($parameters['key']));
 		$value = OC_OCS::readData('post', 'value', 'text');
-		if(OC_Preferences::setValue($user, $app, $key, $value)) {
-			return new OC_OCS_Result(null, 100);
+
+		// update in DB
+		$query = \OCP\DB::prepare('UPDATE `*PREFIX*privatedata` SET `value` = ?  WHERE `user` = ? AND `app` = ? AND `key` = ?');
+		$numRows = $query->execute(array($value, $user, $app, $key));
+                
+		if ($numRows === false || $numRows === 0) {
+			// store in DB
+			$query = \OCP\DB::prepare('INSERT INTO `*PREFIX*privatedata` (`user`, `app`, `key`, `value`)' . ' VALUES(?, ?, ?, ?)');
+			$query->execute(array($user, $app, $key, $value));
 		}
+
+		return new OC_OCS_Result(null, 100);
 	}
 
+	/**
+	 * delete a key
+	 * test: curl http://login:passwd@oc/core/ocs/v1.php/privatedata/deleteattribute/testy/123 --data "post=1"
+	 * @param array $parameters The OCS parameter
+	 * @return \OC_OCS_Result
+	 */
 	public static function delete($parameters) {
-		OC_Util::checkLoggedIn();
 		$user = OC_User::getUser();
+		if (!isset($parameters['app']) or !isset($parameters['key'])) {
+			//key and app are NOT optional here
+			return new OC_OCS_Result(null, 101);
+		}
+
 		$app = addslashes(strip_tags($parameters['app']));
 		$key = addslashes(strip_tags($parameters['key']));
-		if($key==="" or $app==="") {
-			return new OC_OCS_Result(null, 101); //key and app are NOT optional here
-		}
-		if(OC_Preferences::deleteKey($user, $app, $key)) {
-			return new OC_OCS_Result(null, 100);
-		}
+
+		// delete in DB
+		$query = \OCP\DB::prepare('DELETE FROM `*PREFIX*privatedata`  WHERE `user` = ? AND `app` = ? AND `key` = ? ');
+		$query->execute(array($user, $app, $key ));
+
+		return new OC_OCS_Result(null, 100);
 	}
 }
+
diff --git a/tests/lib/ocs/privatedata.php b/tests/lib/ocs/privatedata.php
new file mode 100644
index 0000000000000000000000000000000000000000..ea8413734f17ce916ba906b7e16dafa331af0113
--- /dev/null
+++ b/tests/lib/ocs/privatedata.php
@@ -0,0 +1,141 @@
+<?php
+ /**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2013 Thomas Müller deepdiver@owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+class Test_OC_OCS_Privatedata extends PHPUnit_Framework_TestCase
+{
+
+	private $appKey;
+
+	public function setUp() {
+		\OC::$session->set('user_id', 'user1');
+		$this->appKey = uniqid('app');
+	}
+
+	public function tearDown() {
+	}
+
+	public function testGetEmptyOne() {
+		$params = array('app' => $this->appKey, 'key' => '123');
+		$result = OC_OCS_Privatedata::get($params);
+		$this->assertOcsResult(0, $result);
+	}
+
+	public function testGetEmptyAll() {
+		$params = array('app' => $this->appKey);
+		$result = OC_OCS_Privatedata::get($params);
+		$this->assertOcsResult(0, $result);
+	}
+
+	public function testSetOne() {
+		$_POST = array('value' => 123456789);
+		$params = array('app' => $this->appKey, 'key' => 'k-1');
+		$result = OC_OCS_Privatedata::set($params);
+		$this->assertEquals(100, $result->getStatusCode());
+
+		$result = OC_OCS_Privatedata::get($params);
+		$this->assertOcsResult(1, $result);
+	}
+
+	public function testSetExisting() {
+		$_POST = array('value' => 123456789);
+		$params = array('app' => $this->appKey, 'key' => 'k-10');
+		$result = OC_OCS_Privatedata::set($params);
+		$this->assertEquals(100, $result->getStatusCode());
+
+		$result = OC_OCS_Privatedata::get($params);
+		$this->assertOcsResult(1, $result);
+		$data = $result->getData();
+		$data = $data[0];
+		$this->assertEquals('123456789', $data['value']);
+
+		$_POST = array('value' => 'updated');
+		$params = array('app' => $this->appKey, 'key' => 'k-10');
+		$result = OC_OCS_Privatedata::set($params);
+		$this->assertEquals(100, $result->getStatusCode());
+
+		$result = OC_OCS_Privatedata::get($params);
+		$this->assertOcsResult(1, $result);
+		$data = $result->getData();
+		$data = $data[0];
+		$this->assertEquals('updated', $data['value']);
+	}
+
+	public function testSetMany() {
+		$_POST = array('value' => 123456789);
+
+		// set key 'k-1'
+		$params = array('app' => $this->appKey, 'key' => 'k-1');
+		$result = OC_OCS_Privatedata::set($params);
+		$this->assertEquals(100, $result->getStatusCode());
+
+		// set key 'k-2'
+		$params = array('app' => $this->appKey, 'key' => 'k-2');
+		$result = OC_OCS_Privatedata::set($params);
+		$this->assertEquals(100, $result->getStatusCode());
+
+		// query for all
+		$params = array('app' => $this->appKey);
+		$result = OC_OCS_Privatedata::get($params);
+		$this->assertOcsResult(2, $result);
+	}
+
+	public function testDelete() {
+		$_POST = array('value' => 123456789);
+
+		// set key 'k-1'
+		$params = array('app' => $this->appKey, 'key' => 'k-3');
+		$result = OC_OCS_Privatedata::set($params);
+		$this->assertEquals(100, $result->getStatusCode());
+
+		$result = OC_OCS_Privatedata::delete($params);
+		$this->assertEquals(100, $result->getStatusCode());
+
+		$result = OC_OCS_Privatedata::get($params);
+		$this->assertOcsResult(0, $result);
+	}
+
+	/**
+	 * @dataProvider deleteWithEmptyKeysProvider
+	 */
+	public function testDeleteWithEmptyKeys($params) {
+		$result = OC_OCS_Privatedata::delete($params);
+		$this->assertEquals(101, $result->getStatusCode());
+	}
+
+	public function deleteWithEmptyKeysProvider() {
+		return array(
+			array(array()),
+			array(array('app' => '123')),
+			array(array('key' => '123')),
+		);
+	}
+
+	/**
+	 * @param \OC_OCS_Result $result
+	 */
+	public function assertOcsResult($expectedArraySize, $result) {
+		$this->assertEquals(100, $result->getStatusCode());
+		$data = $result->getData();
+		$this->assertTrue(is_array($data));
+		$this->assertEquals($expectedArraySize, sizeof($data));
+	}
+}
diff --git a/version.php b/version.php
index 1a4672354f6cf351240a676c1fc2120781e2b549..1f3897a093ae6cbf5cd2a3a15db318c2f8686a38 100644
--- a/version.php
+++ b/version.php
@@ -1,7 +1,7 @@
 <?php
 
 // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel when updating major/minor version number.
-$OC_Version=array(6, 00, 0, 3);
+$OC_Version=array(6, 00, 0, 4);
 
 // The human readable string
 $OC_VersionString='6.0 beta 2';